Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/phy/channel/ch_awgn.h
master
Codebot 3 years ago committed by Your Name
commit 9664aa3cf4

@ -382,7 +382,7 @@ macro(ADD_C_COMPILER_FLAG_IF_AVAILABLE flag have)
endmacro(ADD_C_COMPILER_FLAG_IF_AVAILABLE) endmacro(ADD_C_COMPILER_FLAG_IF_AVAILABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-comment -Wno-reorder -Wno-unused-variable -Wtype-limits -std=c++11 -fno-strict-aliasing") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-comment -Wno-reorder -Wno-unused-variable -Wtype-limits -std=c++14 -fno-strict-aliasing")
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE)

@ -692,10 +692,9 @@ int main(int argc, char** argv)
// find the noise spectral density // find the noise spectral density
float snr_lin = srsran_convert_dB_to_power(file_snr); float snr_lin = srsran_convert_dB_to_power(file_snr);
float n0 = abs_avg / snr_lin; float n0 = abs_avg / snr_lin;
float nstd = sqrtf(n0 / 2);
// add some noise to the signal // add some noise to the signal
srsran_ch_awgn_c(output_buffer, output_buffer, nstd, sf_n_samples); srsran_ch_awgn_c(output_buffer, output_buffer, n0, sf_n_samples);
} }
/* send to file or usrp */ /* send to file or usrp */

@ -1001,7 +1001,7 @@ int main(int argc, char** argv)
if (!null_file_sink) { if (!null_file_sink) {
/* Apply AWGN */ /* Apply AWGN */
if (output_file_snr != +INFINITY) { if (output_file_snr != +INFINITY) {
float var = srsran_convert_dB_to_amplitude(-(output_file_snr + 3.0f)); float var = srsran_convert_dB_to_power(-output_file_snr);
for (int k = 0; k < cell.nof_ports; k++) { for (int k = 0; k < cell.nof_ports; k++) {
srsran_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples); srsran_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples);
} }

@ -22,17 +22,14 @@
#ifndef SRSASN_COMMON_UTILS_H #ifndef SRSASN_COMMON_UTILS_H
#define SRSASN_COMMON_UTILS_H #define SRSASN_COMMON_UTILS_H
#include "srsran/common/buffer_pool.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_assert.h" #include "srsran/support/srsran_assert.h"
#include <algorithm>
#include <array> #include <array>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <limits> #include <limits>
#include <map>
#include <string> #include <string>
#include <vector>
namespace asn1 { namespace asn1 {
@ -298,7 +295,8 @@ public:
using iterator = T*; using iterator = T*;
using const_iterator = const T*; using const_iterator = const T*;
explicit bounded_array(uint32_t size_ = 0) : data_(), current_size(size_) {} bounded_array() : data_(), current_size(0) {}
explicit bounded_array(uint32_t size_) : data_(), current_size(size_) {}
static uint32_t capacity() { return MAX_N; } static uint32_t capacity() { return MAX_N; }
uint32_t size() const { return current_size; } uint32_t size() const { return current_size; }
T& operator[](uint32_t idx) { return data_[idx]; } T& operator[](uint32_t idx) { return data_[idx]; }
@ -870,7 +868,8 @@ public:
static const uint32_t lb = LB, ub = UB; static const uint32_t lb = LB, ub = UB;
static const bool has_ext = ext, is_aligned = aligned; static const bool has_ext = ext, is_aligned = aligned;
explicit bitstring(uint32_t siz_ = lb) { resize(siz_); } bitstring() { resize(lb); }
explicit bitstring(uint32_t siz_) { resize(siz_); }
explicit bitstring(const std::string& s) explicit bitstring(const std::string& s)
{ {
resize(s.size()); resize(s.size());
@ -1329,11 +1328,13 @@ public:
~varlength_field_pack_guard(); ~varlength_field_pack_guard();
private: private:
bit_ref brefstart; using byte_array_t = std::array<uint8_t, srsran::byte_buffer_pool::BLOCK_SIZE>;
// bit_ref bref0; using byte_array_ptr = srsran::any_pool_ptr<byte_array_t>;
bit_ref* bref_tracker;
uint8_t buffer[4096]; bit_ref brefstart;
bool align; bit_ref* bref_tracker;
byte_array_ptr buffer_ptr;
bool align;
}; };
class varlength_field_unpack_guard class varlength_field_unpack_guard
@ -1387,7 +1388,7 @@ inline auto to_json(json_writer& j, const T& obj) -> decltype(obj.to_json(j))
} }
template <typename T> template <typename T>
inline void to_json(json_writer& j, const asn1::enumerated<T>& obj) inline auto to_json(json_writer& j, const T& obj) -> decltype(j.write_str(obj.to_string()))
{ {
j.write_str(obj.to_string()); j.write_str(obj.to_string());
} }
@ -1452,6 +1453,423 @@ int test_pack_unpack_consistency(const Msg& msg)
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
/************************
General Layer Types
************************/
/// Enumerated used in RRC and RRC NR that distinguishes Release and Setup modes
struct setup_release_opts {
enum options { release, setup, nulltype } value;
const char* to_string() const
{
static const char* options[] = {"release", "setup"};
return convert_enum_idx(options, 2, value, "setup_release_c::types");
}
};
using setup_release_e = enumerated<setup_release_opts>;
// SetupRelease{ElementTypeParam} ::= CHOICE
template <class T>
struct setup_release_c {
using types_opts = setup_release_opts;
using types = setup_release_e;
// choice methods
setup_release_c() = default;
void set(typename types::options e = types::nulltype) { type_ = e; }
types type() const { return type_; }
SRSASN_CODE pack(bit_ref& bref) const
{
type_.pack(bref);
switch (type_.value) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.pack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
types e;
e.unpack(bref);
set(e);
switch (type_.value) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.unpack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_DECODE_FAIL;
}
return SRSASN_SUCCESS;
}
void to_json(json_writer& j) const
{
j.start_obj();
switch (type_.value) {
case types::release:
break;
case types::setup:
asn1::to_json(j, setup());
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
}
j.end_obj();
}
// getters
bool is_setup() const { return type_.value == setup_release_opts::setup; }
T& setup()
{
assert_choice_type(types::setup, type_, "SetupRelease");
return c;
}
const T& setup() const
{
assert_choice_type(types::setup, type_, "SetupRelease");
return c;
}
void set_release() { set(types::release); }
T& set_setup()
{
set(types::setup);
return c;
}
private:
types type_;
T c;
};
// Criticality ::= ENUMERATED
struct crit_opts {
enum options { reject, ignore, notify, nulltype } value;
const char* to_string() const
{
static const char* options[] = {"reject", "ignore", "notify"};
return convert_enum_idx(options, 3, value, "crit_e");
}
};
typedef enumerated<crit_opts> crit_e;
// Presence ::= ENUMERATED
struct presence_opts {
enum options { optional, conditional, mandatory, nulltype } value;
const char* to_string() const
{
static const char* options[] = {"optional", "conditional", "mandatory"};
return convert_enum_idx(options, 3, value, "presence_e");
}
};
typedef enumerated<presence_opts> presence_e;
namespace detail {
template <typename IEsSetParam>
struct ie_field_value_item {
using obj_set_type = IEsSetParam;
using value_type = typename IEsSetParam::value_c;
const char* item_name() const { return "value"; }
void set_item(uint32_t id) { item = IEsSetParam::get_value(id); }
protected:
value_type item;
};
template <typename ExtensionSetParam>
struct ie_field_ext_item {
using obj_set_type = ExtensionSetParam;
using value_type = typename ExtensionSetParam::ext_c;
const char* item_name() const { return "extension"; }
void set_item(uint32_t id) { item = ExtensionSetParam::get_ext(id); }
protected:
value_type item;
};
template <class IEItem>
struct base_ie_field : public IEItem {
using obj_set_type = typename IEItem::obj_set_type;
using value_type = typename IEItem::value_type;
uint32_t id() const { return obj_set_type::idx_to_id(value().type().value); }
crit_e crit() const { return obj_set_type::get_crit(id()); }
value_type& value() { return this->item; }
const value_type& value() const { return this->item; }
value_type* operator->() { return &value(); }
const value_type* operator->() const { return &value(); }
value_type& operator*() { return value(); }
const value_type& operator*() const { return value(); }
SRSASN_CODE pack(bit_ref& bref) const
{
HANDLE_CODE(pack_integer(bref, id(), (uint32_t)0u, (uint32_t)65535u, false, true));
HANDLE_CODE(crit().pack(bref));
HANDLE_CODE(value().pack(bref));
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
uint32_t id_val;
HANDLE_CODE(unpack_integer(id_val, bref, (uint32_t)0u, (uint32_t)65535u, false, true));
this->set_item(id_val);
HANDLE_CODE(crit().unpack(bref));
HANDLE_CODE(value().unpack(bref));
return SRSASN_SUCCESS;
}
void to_json(json_writer& j) const
{
j.start_obj();
j.write_int("id", id());
j.write_str("criticality", crit().to_string());
j.write_fieldname(this->item_name());
asn1::to_json(j, value());
j.end_obj();
}
bool load_info_obj(const uint32_t& id_)
{
if (not obj_set_type::is_id_valid(id_)) {
return false;
}
this->set_item(id_);
return value().type().value != obj_set_type::value_c::types_opts::nulltype;
}
};
} // namespace detail
// ProtocolIE-Field{LAYER-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE{{IEsSetParam}}
template <class IEsSetParam>
struct protocol_ie_field_s : public detail::base_ie_field<detail::ie_field_value_item<IEsSetParam> > {};
// ProtocolIE-SingleContainer{LAYER-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE{{IEsSetParam}}
template <class ies_set_paramT_>
struct protocol_ie_single_container_s : public protocol_ie_field_s<ies_set_paramT_> {};
// ProtocolExtensionField{LAYER-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE{{LAYER-PROTOCOL-EXTENSION}}
template <class ExtensionSetParam>
struct protocol_ext_field_s : public detail::base_ie_field<detail::ie_field_ext_item<ExtensionSetParam> > {};
namespace detail {
template <typename T>
struct ie_value_item {
using value_type = T;
value_type value;
value_type* operator->() { return &value; }
const value_type* operator->() const { return &value; }
value_type& operator*() { return value; }
const value_type& operator*() const { return value; }
const char* item_name() const { return "value"; }
protected:
value_type& item() { return value; }
const value_type& item() const { return value; }
};
template <typename T>
struct ie_ext_item {
using value_type = T;
value_type ext;
value_type* operator->() { return &ext; }
const value_type* operator->() const { return &ext; }
value_type& operator*() { return ext; }
const value_type& operator*() const { return ext; }
const char* item_name() const { return "extension"; }
protected:
value_type& item() { return ext; }
const value_type& item() const { return ext; }
};
template <class IEItem>
struct base_ie_container_item : public IEItem {
using value_type = typename IEItem::value_type;
base_ie_container_item(uint32_t id_, crit_e crit_) : id(id_), crit(crit_) {}
uint32_t id = 0;
crit_e crit;
value_type* operator->() { return &this->item(); }
const value_type* operator->() const { return &this->item(); }
value_type& operator*() { return this->item(); }
const value_type& operator*() const { return this->item(); }
SRSASN_CODE pack(bit_ref& bref) const
{
HANDLE_CODE(pack_integer(bref, id, (uint32_t)0u, (uint32_t)65535u, false, true));
HANDLE_CODE(crit.pack(bref));
{
varlength_field_pack_guard varlen_scope(bref, true);
HANDLE_CODE(this->item().pack(bref));
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true));
HANDLE_CODE(crit.unpack(bref));
{
varlength_field_unpack_guard varlen_scope(bref, true);
HANDLE_CODE(this->item().unpack(bref));
}
return SRSASN_SUCCESS;
}
void to_json(json_writer& j) const
{
j.start_obj();
j.write_int("id", id);
j.write_str("criticality", crit.to_string());
j.write_fieldname(this->item_name());
asn1::to_json(j, this->item());
j.end_obj();
}
};
} // namespace detail
template <typename T>
struct protocol_ie_container_item_s : public detail::base_ie_container_item<detail::ie_value_item<T> > {
using base_type = detail::base_ie_container_item<detail::ie_value_item<T> >;
using base_type::base_type;
};
template <typename T>
struct protocol_ext_container_item_s : public detail::base_ie_container_item<detail::ie_ext_item<T> > {
using base_type = detail::base_ie_container_item<detail::ie_ext_item<T> >;
using base_type::base_type;
};
// ProtocolIE-Container{LAYER-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE (SIZE (0..65535)) OF ProtocolIE-Field
template <class IEsSetParam>
using protocol_ie_container_l = dyn_seq_of<protocol_ie_field_s<IEsSetParam>, 0, 65535, true>;
// ProtocolExtensionContainer{LAYER-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE (SIZE (1..65535)) OF
// ProtocolExtensionField
template <class ExtensionSetParam>
using protocol_ext_container_l = dyn_seq_of<protocol_ext_field_s<ExtensionSetParam>, 1, 65535, true>;
namespace detail {
struct empty_obj_set_item_c {
struct types_opts {
enum options { nulltype } value;
const char* to_string() const;
};
typedef enumerated<types_opts> types;
// choice methods
types type() const { return types::nulltype; }
SRSASN_CODE pack(bit_ref& bref) const;
SRSASN_CODE unpack(cbit_ref& bref);
void to_json(json_writer& j) const;
};
struct base_empty_obj_set {
// members lookup methods
static uint32_t idx_to_id(uint32_t idx);
static bool is_id_valid(const uint32_t& id);
static crit_e get_crit(const uint32_t& id);
static presence_e get_presence(const uint32_t& id);
};
} // namespace detail
/// Empty Protocol IE Object Set
struct protocol_ies_empty_o : public detail::base_empty_obj_set {
using value_c = detail::empty_obj_set_item_c;
// members lookup methods
static value_c get_value(uint32_t id) { return {}; }
};
/// Empty Protocol Extension Object Set
struct protocol_ext_empty_o : public detail::base_empty_obj_set {
using ext_c = detail::empty_obj_set_item_c;
// members lookup methods
static ext_c get_ext(uint32_t id) { return {}; }
};
/// Empty ProtocolExtensionContainer
struct protocol_ie_container_empty_l {
template <class extT_>
using ie_field_s = protocol_ext_container_item_s<extT_>;
// sequence methods
SRSASN_CODE pack(bit_ref& bref) const
{
uint32_t nof_ies = 0;
pack_length(bref, nof_ies, 1u, 65535u, true);
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
uint32_t nof_ies = 0;
unpack_length(nof_ies, bref, 1u, 65535u, true);
if (nof_ies > 0) {
return SRSASN_ERROR_DECODE_FAIL;
}
return SRSASN_SUCCESS;
}
void to_json(json_writer& j) const
{
j.start_obj();
j.end_obj();
}
};
using protocol_ext_container_empty_l = protocol_ie_container_empty_l;
template <typename ProtocolIEs>
class elementary_procedure_option
{
ProtocolIEs protocol_ies;
public:
bool ext;
// ...
ProtocolIEs* operator->() { return &protocol_ies; }
const ProtocolIEs* operator->() const { return &protocol_ies; }
ProtocolIEs& operator*() { return protocol_ies; }
const ProtocolIEs& operator*() const { return protocol_ies; }
// sequence methods
SRSASN_CODE pack(bit_ref& bref) const
{
bref.pack(ext, 1);
HANDLE_CODE(protocol_ies.pack(bref));
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
bref.unpack(ext, 1);
HANDLE_CODE(protocol_ies.unpack(bref));
return SRSASN_SUCCESS;
}
void to_json(json_writer& j) const
{
j.start_obj();
j.write_fieldname("protocolIEs");
asn1::to_json(j, protocol_ies);
j.end_obj();
}
};
} // namespace asn1 } // namespace asn1
#endif // SRSASN_COMMON_UTILS_H #endif // SRSASN_COMMON_UTILS_H

File diff suppressed because it is too large Load Diff

@ -178,7 +178,7 @@ struct bcch_dl_sch_msg_mbms_s {
}; };
// ThresholdEUTRA-v1250 ::= INTEGER (0..97) // ThresholdEUTRA-v1250 ::= INTEGER (0..97)
using thres_eutra_v1250 = uint8_t; using thres_eutra_v1250 = integer<uint8_t, 0, 97>;
// MBMS-SessionInfo-r9 ::= SEQUENCE // MBMS-SessionInfo-r9 ::= SEQUENCE
struct mbms_session_info_r9_s { struct mbms_session_info_r9_s {

File diff suppressed because it is too large Load Diff

@ -93,6 +93,9 @@ bool make_phy_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type, srsran_
bool make_phy_tdd_cfg(const asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common, bool make_phy_tdd_cfg(const asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common,
srsran_duplex_config_nr_t* srsran_duplex_config_nr); srsran_duplex_config_nr_t* srsran_duplex_config_nr);
bool make_phy_tdd_cfg(const srsran_duplex_config_nr_t& srsran_duplex_config_nr,
srsran_subcarrier_spacing_t scs,
asn1::rrc_nr::tdd_ul_dl_cfg_common_s* tdd_ul_dl_cfg_common);
bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg, bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg,
srsran_harq_ack_cfg_hl_t* srsran_ue_dl_nr_harq_ack_cfg); srsran_harq_ack_cfg_hl_t* srsran_ue_dl_nr_harq_ack_cfg);
bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset); bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset);

File diff suppressed because it is too large Load Diff

@ -31,29 +31,36 @@
namespace asn1 { namespace asn1 {
namespace s1ap { namespace s1ap {
struct init_context_setup_request_s; struct init_context_setup_request_ies_container;
struct ue_context_mod_request_s; using init_context_setup_request_s = elementary_procedure_option<init_context_setup_request_ies_container>;
struct erab_setup_request_s; struct ue_context_mod_request_ies_container;
struct erab_release_cmd_s; using ue_context_mod_request_s = elementary_procedure_option<ue_context_mod_request_ies_container>;
struct erab_modify_request_s; struct erab_setup_request_ies_container;
using erab_setup_request_s = elementary_procedure_option<erab_setup_request_ies_container>;
struct erab_release_cmd_ies_container;
using erab_release_cmd_s = elementary_procedure_option<erab_release_cmd_ies_container>;
struct erab_modify_request_ies_container;
using erab_modify_request_s = elementary_procedure_option<erab_modify_request_ies_container>;
struct ue_paging_id_c; struct ue_paging_id_c;
struct ho_request_s; struct ho_request_ies_container;
using ho_request_s = elementary_procedure_option<ho_request_ies_container>;
struct sourceenb_to_targetenb_transparent_container_s; struct sourceenb_to_targetenb_transparent_container_s;
struct init_context_setup_resp_s; struct init_context_setup_resp_ies_container;
struct erab_setup_resp_s; using init_context_setup_resp_s = elementary_procedure_option<init_context_setup_resp_ies_container>;
struct erab_setup_resp_ies_container;
using erab_setup_resp_s = elementary_procedure_option<erab_setup_resp_ies_container>;
struct rrc_establishment_cause_opts; struct rrc_establishment_cause_opts;
struct cause_radio_network_opts; struct cause_radio_network_opts;
struct bearers_subject_to_status_transfer_item_ies_o; struct bearers_subject_to_status_transfer_item_ies_o;
struct erab_level_qos_params_s; struct erab_level_qos_params_s;
struct ho_cmd_s; struct ho_cmd_ies_container;
using ho_cmd_s = elementary_procedure_option<ho_cmd_ies_container>;
struct erab_admitted_item_s; struct erab_admitted_item_s;
struct erab_to_be_modified_item_bearer_mod_req_s; struct erab_to_be_modified_item_bearer_mod_req_s;
struct cause_c; struct cause_c;
struct erab_item_s; struct erab_item_s;
struct ue_aggregate_maximum_bitrate_s; struct ue_aggregate_maximum_bitrate_s;
template <class ies_set_paramT_>
struct protocol_ie_single_container_s;
using bearers_subject_to_status_transfer_list_l = using bearers_subject_to_status_transfer_list_l =
dyn_array<protocol_ie_single_container_s<bearers_subject_to_status_transfer_item_ies_o> >; dyn_array<protocol_ie_single_container_s<bearers_subject_to_status_transfer_item_ies_o> >;
using rrc_establishment_cause_e = enumerated<rrc_establishment_cause_opts, true, 3>; using rrc_establishment_cause_e = enumerated<rrc_establishment_cause_opts, true, 3>;

@ -89,7 +89,7 @@ public:
* @param scs SSB Subcarrier spacing * @param scs SSB Subcarrier spacing
* @return The SSB pattern case if band and subcarrier spacing match, SRSRAN_SSB_PATTERN_INVALID otherwise * @return The SSB pattern case if band and subcarrier spacing match, SRSRAN_SSB_PATTERN_INVALID otherwise
*/ */
srsran_ssb_patern_t get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) const; static srsran_ssb_patern_t get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs);
/** /**
* @brief Select the lower SSB subcarrier spacing valid for this band * @brief Select the lower SSB subcarrier spacing valid for this band

@ -166,8 +166,10 @@ private:
uint32_t capacity; uint32_t capacity;
}; };
/// Type of global byte buffer pool
using byte_buffer_pool = concurrent_fixed_memory_pool<sizeof(byte_buffer_t)>; using byte_buffer_pool = concurrent_fixed_memory_pool<sizeof(byte_buffer_t)>;
/// Function used to generate unique byte buffers
inline unique_byte_buffer_t make_byte_buffer() noexcept inline unique_byte_buffer_t make_byte_buffer() noexcept
{ {
return std::unique_ptr<byte_buffer_t>(new (std::nothrow) byte_buffer_t()); return std::unique_ptr<byte_buffer_t>(new (std::nothrow) byte_buffer_t());
@ -206,12 +208,30 @@ inline unique_byte_buffer_t make_byte_buffer(const uint8_t* payload, uint32_t le
namespace detail { namespace detail {
template <typename T>
struct byte_buffer_pool_deleter { struct byte_buffer_pool_deleter {
void operator()(void* ptr) { byte_buffer_pool::get_instance()->deallocate_node(ptr); } void operator()(T* ptr) const { byte_buffer_pool::get_instance()->deallocate_node(ptr); }
}; };
} // namespace detail } // namespace detail
/// Unique ptr to global byte buffer pool
template <typename T>
using buffer_pool_ptr = std::unique_ptr<T, detail::byte_buffer_pool_deleter<T> >;
/// Method to create unique_ptrs of type T allocated in global byte buffer pool
template <typename T, typename... CtorArgs>
buffer_pool_ptr<T> make_buffer_pool_obj(CtorArgs&&... args) noexcept
{
static_assert(sizeof(T) <= byte_buffer_pool::BLOCK_SIZE, "pool_bounded_vector does not fit buffer pool block size");
void* memblock = byte_buffer_pool::get_instance()->allocate_node(sizeof(T));
if (memblock == nullptr) {
return buffer_pool_ptr<T>();
}
new (memblock) T(std::forward<CtorArgs>(args)...);
return buffer_pool_ptr<T>(static_cast<T*>(memblock), detail::byte_buffer_pool_deleter<T>());
}
/** /**
* Class to wrap objects of type T which get allocated/deallocated using the byte_buffer_pool * Class to wrap objects of type T which get allocated/deallocated using the byte_buffer_pool
* @tparam T type of the object being allocated * @tparam T type of the object being allocated
@ -239,21 +259,19 @@ public:
template <typename... CtorArgs> template <typename... CtorArgs>
static byte_buffer_pool_ptr<T> make(CtorArgs&&... args) static byte_buffer_pool_ptr<T> make(CtorArgs&&... args)
{ {
void* memblock = byte_buffer_pool::get_instance()->allocate_node(sizeof(T));
if (memblock == nullptr) {
return byte_buffer_pool_ptr<T>();
}
new (memblock) T(std::forward<CtorArgs>(args)...);
byte_buffer_pool_ptr<T> ret; byte_buffer_pool_ptr<T> ret;
ret.ptr = std::unique_ptr<T, detail::byte_buffer_pool_deleter>(static_cast<T*>(memblock), ret.ptr = make_buffer_pool_obj<T>(std::forward<CtorArgs>(args)...);
detail::byte_buffer_pool_deleter());
return ret; return ret;
}; };
private: private:
std::unique_ptr<T, detail::byte_buffer_pool_deleter> ptr; buffer_pool_ptr<T> ptr;
}; };
/// unique_ptr with virtual deleter, so it can be used by any pool
template <typename T>
using any_pool_ptr = std::unique_ptr<T, std::function<void(T*)> >;
} // namespace srsran } // namespace srsran
#endif // SRSRAN_BUFFER_POOL_H #endif // SRSRAN_BUFFER_POOL_H

@ -191,9 +191,18 @@ uint8_t security_generate_k_seaf(const uint8_t* k_ausf, const char* serving_netw
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_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,
const uint8_t* k_enb,
const uint32_t pci_,
const uint32_t earfcn_,
uint8_t* k_enb_star);
uint8_t uint8_t
security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci, const uint32_t earfcn, uint8_t* k_enb_star); security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci, const uint32_t earfcn, uint8_t* k_enb_star);
uint8_t
security_generate_k_gnb_star(const uint8_t* k_gnb, const uint32_t pci_, const uint32_t dl_arfcn_, uint8_t* k_gnb_star);
uint8_t security_generate_nh(const uint8_t* k_asme, const uint8_t* sync, uint8_t* nh); uint8_t security_generate_nh(const uint8_t* k_asme, const uint8_t* sync, uint8_t* nh);
uint8_t security_generate_k_nas(const uint8_t* k_asme, uint8_t security_generate_k_nas(const uint8_t* k_asme,

@ -191,7 +191,7 @@ public:
* @param rnti the UE identifier in the eNb * @param rnti the UE identifier in the eNb
* @param cc_idx the eNb Cell/Carrier identifier * @param cc_idx the eNb Cell/Carrier identifier
* @param nof_bytes the number of grants carrierd by the PUSCH message * @param nof_bytes the number of grants carrierd by the PUSCH message
* @param crc_res the CRC check, set to true if the message was decoded succesfully * @param crc_res the CRC check, set to true if the message was decoded successfully
* @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs
*/ */
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res) = 0; virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res) = 0;
@ -203,7 +203,7 @@ public:
* @param rnti the UE identifier in the eNb * @param rnti the UE identifier in the eNb
* @param enb_cc_idx the eNb Cell/Carrier identifier * @param enb_cc_idx the eNb Cell/Carrier identifier
* @param nof_bytes the number of grants carrierd by the PUSCH message * @param nof_bytes the number of grants carrierd by the PUSCH message
* @param crc_res the CRC check, set to true if the message was decoded succesfully * @param crc_res the CRC check, set to true if the message was decoded successfully
* @param ul_nof_prbs Number of PRBs allocated to grant * @param ul_nof_prbs Number of PRBs allocated to grant
* @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs
*/ */

@ -61,6 +61,7 @@ struct cell_cfg_t {
uint32_t cell_id; uint32_t cell_id;
uint16_t tac; uint16_t tac;
uint32_t pci; uint32_t pci;
double tx_gain;
uint16_t root_seq_idx; uint16_t root_seq_idx;
uint32_t dl_earfcn; uint32_t dl_earfcn;
double dl_freq_hz; double dl_freq_hz;

@ -154,9 +154,9 @@ public:
virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::byte_buffer_t& buffer) = 0; virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::byte_buffer_t& buffer) = 0;
/// User management /// User management
virtual int add_user(uint16_t rnti, const sched_nr_ue_cfg_t& uecfg) = 0; virtual int add_user(uint16_t rnti, uint32_t pcell_cc_idx) = 0;
virtual int update_user(uint16_t new_rnti, uint16_t old_rnti) = 0; virtual int update_user(uint16_t new_rnti, uint16_t old_rnti) = 0;
virtual void set_activity_user(uint16_t rnti) = 0; virtual void set_activity_user(uint16_t rnti) = 0;
}; };
// NR interface is almost identical to EUTRA version // NR interface is almost identical to EUTRA version

@ -31,7 +31,7 @@ class mac_interface_rrc_nr
{ {
public: public:
// Provides cell configuration including SIB periodicity, etc. // Provides cell configuration including SIB periodicity, etc.
virtual int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) = 0; virtual int cell_cfg(const std::vector<sched_nr_cell_cfg_t>& nr_cells) = 0;
/// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise. /// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise.
virtual uint16_t reserve_rnti(uint32_t enb_cc_idx, const sched_nr_interface::ue_cfg_t& uecfg) = 0; virtual uint16_t reserve_rnti(uint32_t enb_cc_idx, const sched_nr_interface::ue_cfg_t& uecfg) = 0;

@ -42,9 +42,10 @@ public:
* @brief Describes a cell search result * @brief Describes a cell search result
*/ */
struct cell_search_result_t { struct cell_search_result_t {
bool cell_found = false; bool cell_found = false;
uint32_t pci = 0; ///< Physical Cell Identifier uint32_t ssb_arfcn = 0; ///< SSB center ARFCN
srsran_pbch_msg_nr_t pbch_msg; ///< Packed PBCH message for the upper layers uint32_t pci = 0; ///< Physical Cell Identifier
srsran_pbch_msg_nr_t pbch_msg = {}; ///< Packed PBCH message for the upper layers
srsran_csi_trs_measurements_t measurements = {}; ///< Measurements from SSB block srsran_csi_trs_measurements_t measurements = {}; ///< Measurements from SSB block
}; };
@ -53,6 +54,23 @@ public:
* @param result Cell search result completion * @param result Cell search result completion
*/ */
virtual void cell_search_found_cell(const cell_search_result_t& result) = 0; virtual void cell_search_found_cell(const cell_search_result_t& result) = 0;
/**
* @brief Describes a cell select result
*/
struct cell_select_result_t {
enum {
ERROR = 0, ///< The cell selection procedure failed due a to an invalid configuration
UNSUCCESSFUL, ///< The cell selection failed to find and synchronise the SSB
SUCCESSFUL, ///< The cell selection was successful, resulting in a camping state
} status;
};
/**
* @brief Informs RRC about cell select process completion
* @param result Cell select result completion
*/
virtual void cell_select_completed(const cell_select_result_t& result) = 0;
}; };
class mac_interface_phy_nr class mac_interface_phy_nr
@ -191,22 +209,25 @@ public:
}; };
struct phy_args_nr_t { struct phy_args_nr_t {
uint32_t rf_channel_offset = 0; ///< Specifies the RF channel the NR carrier shall fill uint32_t rf_channel_offset = 0; ///< Specifies the RF channel the NR carrier shall fill
uint32_t nof_carriers = 1; uint32_t nof_carriers = 1;
uint32_t max_nof_prb = 106; uint32_t max_nof_prb = 106;
uint32_t nof_phy_threads = 3; double srate_hz = 23.04e6;
uint32_t worker_cpu_mask = 0; uint32_t nof_phy_threads = 3;
srsran::phy_log_args_t log = {}; uint32_t worker_cpu_mask = 0;
srsran_ue_dl_nr_args_t dl = {}; int slot_recv_thread_prio = 0; /// Specifies the slot receive thread priority, RT by default
srsran_ue_ul_nr_args_t ul = {}; int workers_thread_prio = 2; /// Specifies the workers thread priority, RT by default
std::set<uint32_t> fixed_sr = {1}; srsran::phy_log_args_t log = {};
uint32_t fix_wideband_cqi = 15; ///< Set to a non-zero value for fixing the wide-band CQI report srsran_ue_dl_nr_args_t dl = {};
bool store_pdsch_ko = false; srsran_ue_ul_nr_args_t ul = {};
float trs_epre_ema_alpha = 0.1f; ///< EPRE measurement exponential average alpha std::set<uint32_t> fixed_sr = {1};
float trs_rsrp_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha uint32_t fix_wideband_cqi = 15; ///< Set to a non-zero value for fixing the wide-band CQI report
float trs_sinr_ema_alpha = 0.1f; ///< SINR measurement exponential average alpha bool store_pdsch_ko = false;
float trs_cfo_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha float trs_epre_ema_alpha = 0.1f; ///< EPRE measurement exponential average alpha
bool enable_worker_cfo = true; ///< Enable/Disable open loop CFO correction at the workers float trs_rsrp_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha
float trs_sinr_ema_alpha = 0.1f; ///< SINR measurement exponential average alpha
float trs_cfo_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha
bool enable_worker_cfo = true; ///< Enable/Disable open loop CFO correction at the workers
phy_args_nr_t() phy_args_nr_t()
{ {
@ -286,7 +307,6 @@ public:
* @brief Describes cell search arguments * @brief Describes cell search arguments
*/ */
struct cell_search_args_t { struct cell_search_args_t {
double srate_hz;
double center_freq_hz; double center_freq_hz;
double ssb_freq_hz; double ssb_freq_hz;
srsran_subcarrier_spacing_t ssb_scs; srsran_subcarrier_spacing_t ssb_scs;

@ -1,31 +1,17 @@
/** /**
* Copyright 2013-2021 Software Radio Systems Limited * \copyright Copyright 2013-2021 Software Radio Systems Limited
* *
* This file is part of srsRAN. * \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
* srsRAN is free software: you can redistribute it and/or modify * the distribution.
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
* *
*/ */
/********************************************************************************************** /**
* File: ch_awgn.h * \file ch_awgn.h
* * \brief Additive white Gaussian noise channel object
* Description: Additive white gaussian noise channel object
* *
* Reference: */
*********************************************************************************************/
#include "srsran/config.h" #include "srsran/config.h"
#include <stdint.h> #include <stdint.h>
@ -38,7 +24,7 @@ extern "C" {
#endif #endif
/** /**
* The srsRAN channel AWGN implements an efficient Box-Muller Method accelerated with SIMD. * \brief srsRAN channel AWGN implements an efficient Box-Muller Method accelerated with SIMD.
*/ */
typedef struct { typedef struct {
float* table_cos; float* table_cos;
@ -48,7 +34,7 @@ typedef struct {
} srsran_channel_awgn_t; } srsran_channel_awgn_t;
/** /**
* Initialization function of the channel AWGN object * \brief function of the channel AWGN object
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param seed random generator seed * @param seed random generator seed
@ -56,7 +42,7 @@ typedef struct {
SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed); SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed);
/** /**
* Sets the noise level N0 in decibels full scale (dBfs) * \brief the noise level N0 in decibels full scale (dBfs)
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param n0_dBfs noise level * @param n0_dBfs noise level
@ -64,7 +50,7 @@ SRSRAN_API int srsran_channel_awgn_init(srsran_channel_awgn_t* q, uint32_t seed)
SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBfs); SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBfs);
/** /**
* Runs the complex AWGN channel * \brief the complex AWGN channel
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param in complex input array * @param in complex input array
@ -74,7 +60,7 @@ SRSRAN_API int srsran_channel_awgn_set_n0(srsran_channel_awgn_t* q, float n0_dBf
SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t* in, cf_t* out, uint32_t length); SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t* in, cf_t* out, uint32_t length);
/** /**
* Runs the real AWGN channel * \brief the real AWGN channel
* *
* @param q AWGN channel object * @param q AWGN channel object
* @param in real input array * @param in real input array
@ -84,15 +70,31 @@ SRSRAN_API void srsran_channel_awgn_run_c(srsran_channel_awgn_t* q, const cf_t*
SRSRAN_API void srsran_channel_awgn_run_f(srsran_channel_awgn_t* q, const float* in, float* out, uint32_t length); SRSRAN_API void srsran_channel_awgn_run_f(srsran_channel_awgn_t* q, const float* in, float* out, uint32_t length);
/** /**
* Free AWGN channel generator data * \brief AWGN channel generator data
* *
* @param q AWGN channel object * @param q AWGN channel object
*/ */
SRSRAN_API void srsran_channel_awgn_free(srsran_channel_awgn_t* q); SRSRAN_API void srsran_channel_awgn_free(srsran_channel_awgn_t* q);
/**
* \brief signal \p input with AWGN to obtain signal \p output (complex case).
*
* @param[in] input Input signal
* @param[out] output Output signal
* @param[in] variance Noise variance
* @param[in] len Number of samples
*/
SRSRAN_API void srsran_ch_awgn_c(const cf_t* input, cf_t* output, float variance, uint32_t len); SRSRAN_API void srsran_ch_awgn_c(const cf_t* input, cf_t* output, float variance, uint32_t len);
SRSRAN_API void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len); /**
* \brief Perturb signal \p input with AWGN to obtain signal \p output (real case).
*
* @param[in] input Input signal
* @param[out] output Output signal
* @param[in] variance Noise variance
* @param[in] len Number of samples
*/
SRSRAN_API void srsran_ch_awgn_f(const float* input, float* output, float variance, uint32_t len);
SRSRAN_API float srsran_ch_awgn_get_variance(float ebno_db, float rate); SRSRAN_API float srsran_ch_awgn_get_variance(float ebno_db, float rate);

@ -507,7 +507,7 @@ SRSRAN_API char* srsran_nbiot_mode_string(srsran_nbiot_mode_t mode);
* Returns a constant string pointer with the ACK/NACK feedback mode * Returns a constant string pointer with the ACK/NACK feedback mode
* *
* @param ack_nack_feedback_mode Mode * @param ack_nack_feedback_mode Mode
* @return Returns constant pointer with the text of the mode if succesful, `error` otherwise * @return Returns constant pointer with the text of the mode if successful, `error` otherwise
*/ */
SRSRAN_API const char* srsran_ack_nack_feedback_mode_string(srsran_ack_nack_feedback_mode_t ack_nack_feedback_mode); SRSRAN_API const char* srsran_ack_nack_feedback_mode_string(srsran_ack_nack_feedback_mode_t ack_nack_feedback_mode);
@ -515,7 +515,7 @@ SRSRAN_API const char* srsran_ack_nack_feedback_mode_string(srsran_ack_nack_feed
* Returns a constant string pointer with the ACK/NACK feedback mode * Returns a constant string pointer with the ACK/NACK feedback mode
* *
* @param ack_nack_feedback_mode Mode * @param ack_nack_feedback_mode Mode
* @return Returns constant pointer with the text of the mode if succesful, `error` otherwise * @return Returns constant pointer with the text of the mode if successful, `error` otherwise
*/ */
SRSRAN_API srsran_ack_nack_feedback_mode_t srsran_string_ack_nack_feedback_mode(const char* str); SRSRAN_API srsran_ack_nack_feedback_mode_t srsran_string_ack_nack_feedback_mode(const char* str);

@ -62,7 +62,8 @@ SRSRAN_API int srsran_softbuffer_rx_init(srsran_softbuffer_rx_t* q, uint32_t nof
* @param q The Rx soft-buffer pointer * @param q The Rx soft-buffer pointer
* @param max_cb The maximum number of code blocks to allocate * @param max_cb The maximum number of code blocks to allocate
* @param max_cb_size The code block size to allocate * @param max_cb_size The code block size to allocate
* @return It returns SRSRAN_SUCCESS if it allocates the soft-buffer succesfully, otherwise it returns SRSRAN_ERROR code * @return It returns SRSRAN_SUCCESS if it allocates the soft-buffer successfully, otherwise it returns SRSRAN_ERROR
* code
*/ */
SRSRAN_API int srsran_softbuffer_rx_init_guru(srsran_softbuffer_rx_t* q, uint32_t max_cb, uint32_t max_cb_size); SRSRAN_API int srsran_softbuffer_rx_init_guru(srsran_softbuffer_rx_t* q, uint32_t max_cb, uint32_t max_cb_size);
@ -90,7 +91,8 @@ SRSRAN_API int srsran_softbuffer_tx_init(srsran_softbuffer_tx_t* q, uint32_t nof
* @param q The Tx soft-buffer pointer * @param q The Tx soft-buffer pointer
* @param max_cb The maximum number of code blocks to allocate * @param max_cb The maximum number of code blocks to allocate
* @param max_cb_size The code block size to allocate * @param max_cb_size The code block size to allocate
* @return It returns SRSRAN_SUCCESS if it allocates the soft-buffer succesfully, otherwise it returns SRSRAN_ERROR code * @return It returns SRSRAN_SUCCESS if it allocates the soft-buffer successfully, otherwise it returns SRSRAN_ERROR
* code
*/ */
SRSRAN_API int srsran_softbuffer_tx_init_guru(srsran_softbuffer_tx_t* q, uint32_t max_cb, uint32_t max_cb_size); SRSRAN_API int srsran_softbuffer_tx_init_guru(srsran_softbuffer_tx_t* q, uint32_t max_cb, uint32_t max_cb_size);

@ -87,7 +87,7 @@ SRSRAN_API uint32_t srsran_pucch_proc_get_npucch(const srsran_cell_t* cell,
* @param uci_cfg uplink control information configuration * @param uci_cfg uplink control information configuration
* @param j selected channel * @param j selected channel
* @param b received bits * @param b received bits
* @return Returns SRSRAN_SUCCESS if it can decode it succesfully, SRSRAN_ERROR code otherwise * @return Returns SRSRAN_SUCCESS if it can decode it successfully, SRSRAN_ERROR code otherwise
*/ */
SRSRAN_API int srsran_pucch_cs_get_ack(const srsran_pucch_cfg_t* cfg, SRSRAN_API int srsran_pucch_cs_get_ack(const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg, const srsran_uci_cfg_t* uci_cfg,

@ -278,4 +278,6 @@ SRSRAN_API uint32_t srsran_ssb_candidate_sf_idx(const srsran_ssb_t* q, uint32_t
*/ */
SRSRAN_API uint32_t srsran_ssb_candidate_sf_offset(const srsran_ssb_t* q, uint32_t ssb_idx); SRSRAN_API uint32_t srsran_ssb_candidate_sf_offset(const srsran_ssb_t* q, uint32_t ssb_idx);
SRSRAN_API uint32_t srsran_ssb_cfg_to_str(const srsran_ssb_cfg_t* cfg, char* str, uint32_t str_len);
#endif // SRSRAN_SSB_H #endif // SRSRAN_SSB_H

@ -62,7 +62,7 @@ typedef struct SRSRAN_API {
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
srsran_ssb_cfg_t ssb; ///< SSB configuration srsran_ssb_cfg_t ssb; ///< SSB configuration
uint32_t N_id; ///< Physicall cell identifier uint32_t N_id; ///< Physical cell identifier
} srsran_ue_sync_nr_cfg_t; } srsran_ue_sync_nr_cfg_t;
/** /**

@ -110,7 +110,7 @@ private:
std::array<std::vector<cf_t>, SRSRAN_MAX_CHANNELS> rx_buffer; std::array<std::vector<cf_t>, SRSRAN_MAX_CHANNELS> rx_buffer;
std::array<srsran_resampler_fft_t, SRSRAN_MAX_CHANNELS> interpolators = {}; std::array<srsran_resampler_fft_t, SRSRAN_MAX_CHANNELS> interpolators = {};
std::array<srsran_resampler_fft_t, SRSRAN_MAX_CHANNELS> decimators = {}; std::array<srsran_resampler_fft_t, SRSRAN_MAX_CHANNELS> decimators = {};
bool decimator_busy = false; ///< Indicates the decimator is changing the rate std::atomic<bool> decimator_busy = {false}; ///< Indicates the decimator is changing the rate
rf_timestamp_t end_of_burst_time = {}; rf_timestamp_t end_of_burst_time = {};
std::atomic<bool> is_start_of_burst{false}; std::atomic<bool> is_start_of_burst{false};

@ -0,0 +1,297 @@
/**
*
* \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 "channel_mapping.h"
#include "radio_metrics.h"
#include "rf_buffer.h"
#include "rf_timestamp.h"
#include "srsran/common/interfaces_common.h"
#include "srsran/interfaces/radio_interfaces.h"
#include "srsran/phy/resampling/resampler.h"
#include "srsran/phy/rf/rf.h"
#include "srsran/radio/radio_base.h"
#include "srsran/srslog/srslog.h"
#include "srsran/srsran.h"
#include <condition_variable>
#include <list>
#include <string>
#ifndef SRSRAN_RADIO_DUMMY_H
#define SRSRAN_RADIO_DUMMY_H
namespace srsran {
/**
* Implementation of radio dummy for the PHY testing
*
* It uses ringbuffers from srsRAN library to emulate baseband transmission and reception. The current implementation
* does not support dynamic sampling rates, gains and frequencies.
*/
class radio_dummy : public srsran::radio_base, public srsran::radio_interface_phy
{
private:
static const uint32_t TEMP_BUFFER_SZ = SRSRAN_SF_LEN_MAX * SRSRAN_NOF_SF_X_FRAME;
srslog::basic_logger& logger;
std::vector<srsran_ringbuffer_t> rx_ring_buffers;
std::vector<srsran_ringbuffer_t> tx_ring_buffers;
std::mutex tx_mutex;
std::atomic<double> srate_hz = {0.0f};
std::atomic<float> rx_gain = {1.0f};
std::atomic<float> tx_gain = {1.0f};
cf_t* temp_buffer = nullptr;
uint64_t rx_timestamp = 0;
uint64_t tx_timestamp = 0;
srsran_rf_info_t rf_info = {};
std::atomic<bool> is_initialised = {false};
std::atomic<bool> quit = {false};
void write_ring_buffers(std::vector<srsran_ringbuffer_t>& buffers, cf_t** buffer, uint32_t nsamples)
{
for (uint32_t i = 0; i < buffers.size(); i++) {
int ret = SRSRAN_SUCCESS;
do {
if (ret != SRSRAN_SUCCESS) {
logger.error("Ring buffer write failed (full). Trying again.");
}
ret = srsran_ringbuffer_write_timed(&buffers[i], buffer[i], (int)(sizeof(cf_t) * nsamples), 1000);
} while (ret == SRSRAN_ERROR_TIMEOUT and not quit);
}
}
void read_ring_buffers(std::vector<srsran_ringbuffer_t>& buffers, cf_t** buffer, uint32_t nsamples)
{
for (uint32_t i = 0; i < buffers.size(); i++) {
int ret = SRSRAN_SUCCESS;
do {
if (ret != SRSRAN_SUCCESS) {
logger.error("Ring buffer read failed. Trying again.");
}
ret = srsran_ringbuffer_read_timed(&buffers[i], buffer[i], (int)(sizeof(cf_t) * nsamples), 1000);
} while (ret == SRSRAN_ERROR_TIMEOUT and not quit);
}
}
void write_zeros_ring_buffers(std::vector<srsran_ringbuffer_t>& buffers, uint32_t nsamples)
{
uint32_t n = SRSRAN_MIN(nsamples, TEMP_BUFFER_SZ);
srsran_vec_cf_zero(temp_buffer, n);
std::array<cf_t*, SRSRAN_MAX_CHANNELS> zero_buffer_pointers = {};
for (cf_t*& ptr : zero_buffer_pointers) {
ptr = temp_buffer;
}
while (nsamples > 0) {
// Get new number of samples
n = SRSRAN_MIN(nsamples, TEMP_BUFFER_SZ);
// Write zeros in the buffers
write_ring_buffers(buffers, zero_buffer_pointers.data(), n);
nsamples -= n;
}
}
void advance_tx_timestamp(uint64_t ts, bool round_sf = false)
{
std::lock_guard<std::mutex> lock(tx_mutex);
// Make sure new timestamp has not passed
if (ts < tx_timestamp) {
return;
}
// Calculate transmission gap
uint32_t tx_gap = (uint32_t)(ts - tx_timestamp);
// Round gap to subframe size
if (round_sf) {
uint64_t sf_sz = (uint64_t)(srate_hz / 1e3);
tx_gap = sf_sz * SRSRAN_CEIL(tx_gap, sf_sz);
}
// Skip zeros if there is no gap
if (tx_gap == 0) {
return;
}
// Write zeros in tx ring buffer
write_zeros_ring_buffers(tx_ring_buffers, tx_gap);
// Update new transmit timestamp
tx_timestamp += tx_gap;
}
public:
radio_dummy() : logger(srslog::fetch_basic_logger("RF", false)) {}
~radio_dummy()
{
for (auto& rb : rx_ring_buffers) {
srsran_ringbuffer_free(&rb);
}
for (auto& rb : tx_ring_buffers) {
srsran_ringbuffer_free(&rb);
}
if (temp_buffer) {
free(temp_buffer);
}
}
std::string get_type() override { return "dummy"; }
int init(const rf_args_t& args_, phy_interface_radio* phy_) override
{
// Set logger level
logger.set_level(srslog::str_to_basic_level(args_.log_level));
// Get base sampling rate and assert the value is valid
srate_hz = args_.srate_hz;
if (not std::isnormal(srate_hz)) {
logger.error("A valid sampling rate is missing");
return SRSRAN_ERROR;
}
// Create receiver ring buffers
rx_ring_buffers.resize(args_.nof_carriers * args_.nof_antennas);
for (auto& rb : rx_ring_buffers) {
if (srsran_ringbuffer_init(&rb, (int)sizeof(cf_t) * TEMP_BUFFER_SZ) != SRSRAN_SUCCESS) {
perror("init softbuffer");
}
}
// Create transmitter ring buffers
tx_ring_buffers.resize(args_.nof_carriers * args_.nof_antennas);
for (auto& rb : tx_ring_buffers) {
if (srsran_ringbuffer_init(&rb, (int)sizeof(cf_t) * TEMP_BUFFER_SZ) != SRSRAN_SUCCESS) {
perror("init softbuffer");
}
}
// Create temporal buffer
temp_buffer = srsran_vec_cf_malloc(TEMP_BUFFER_SZ);
if (!temp_buffer) {
perror("malloc");
}
// Set RF Info (in dB)
rf_info.min_rx_gain = 0.0f;
rf_info.max_rx_gain = 90.0f;
rf_info.min_tx_gain = 0.0f;
rf_info.max_tx_gain = 90.0f;
// Finally, the radio is initialised
is_initialised = true;
return SRSRAN_SUCCESS;
}
void stop() override { quit = true; }
bool get_metrics(rf_metrics_t* metrics) override { return false; }
void set_loglevel(std::string& str) { logger.set_level(srslog::str_to_basic_level(str)); }
void write_rx(cf_t** buffer, uint32_t nsamples) { write_ring_buffers(rx_ring_buffers, buffer, nsamples); }
void read_tx(cf_t** buffer, uint32_t nsamples) { read_ring_buffers(tx_ring_buffers, buffer, nsamples); }
bool tx(srsran::rf_buffer_interface& buffer, const srsran::rf_timestamp_interface& tx_time) override
{
bool ret = true;
// Convert timestamp to samples
uint64_t tx_time_n = srsran_timestamp_uint64(&tx_time.get(0), srate_hz);
// Check if the transmission is in the past
{
std::lock_guard<std::mutex> lock(tx_mutex);
if (tx_time_n < tx_timestamp) {
logger.error("Error transmission in the past for %d samples", (int)(tx_timestamp - tx_time_n));
return false;
}
}
// Advance TX to timestamp
advance_tx_timestamp(tx_time_n);
// From now on, protect buffers
std::lock_guard<std::mutex> lock(tx_mutex);
// Write transmission buffers into the ring buffer
write_ring_buffers(tx_ring_buffers, buffer.to_cf_t(), buffer.get_nof_samples());
// Increment transmit timestamp
tx_timestamp += buffer.get_nof_samples();
return ret;
}
void release_freq(const uint32_t& carrier_idx) override{};
void tx_end() override {}
bool rx_now(srsran::rf_buffer_interface& buffer, srsran::rf_timestamp_interface& rxd_time) override
{
// Advance Tx buffer
advance_tx_timestamp(rx_timestamp + buffer.get_nof_samples(), true);
// Read samples
read_ring_buffers(rx_ring_buffers, buffer.to_cf_t(), buffer.get_nof_samples());
// Apply Rx gain
for (uint32_t i = 0; i < rx_ring_buffers.size(); i++) {
cf_t* ptr = buffer.get(i);
srsran_vec_sc_prod_cfc(ptr, rx_gain, ptr, buffer.get_nof_samples());
}
// Set Rx timestamp
srsran_timestamp_init_uint64(rxd_time.get_ptr(0), rx_timestamp, (double)srate_hz);
// Advance timestamp
rx_timestamp += buffer.get_nof_samples();
return true;
}
void set_tx_freq(const uint32_t& channel_idx, const double& freq) override
{
logger.info("Set Tx freq to %+.0f MHz.", freq * 1.0e-6);
}
void set_rx_freq(const uint32_t& channel_idx, const double& freq) override
{
logger.info("Set Rx freq to %+.0f MHz.", freq * 1.0e-6);
}
void set_rx_gain_th(const float& gain) override
{
rx_gain = srsran_convert_dB_to_amplitude(gain);
logger.info("Set Rx gain-th to %+.1f dB (%.6f).", gain, rx_gain.load());
}
void set_tx_gain(const float& gain) override
{
tx_gain = srsran_convert_dB_to_amplitude(gain);
logger.info("Set Tx gain to %+.1f dB (%.6f).", gain, tx_gain.load());
}
void set_rx_gain(const float& gain) override
{
rx_gain = srsran_convert_dB_to_amplitude(gain);
logger.info("Set Rx gain to %+.1f dB (%.6f).", gain, rx_gain.load());
}
void set_tx_srate(const double& srate) override { logger.info("Set Tx sampling rate to %+.3f MHz.", srate * 1.0e-6); }
void set_rx_srate(const double& srate) override { logger.info("Set Rx sampling rate to %+.3f MHz.", srate * 1.0e-6); }
void set_channel_rx_offset(uint32_t ch, int32_t offset_samples) override{};
float get_rx_gain() override { return srsran_convert_amplitude_to_dB(rx_gain); }
double get_freq_offset() override { return 0; }
bool is_continuous_tx() override { return false; }
bool get_is_start_of_burst() override { return false; }
bool is_init() override { return is_initialised; }
void reset() override {}
srsran_rf_info_t* get_info() override { return &rf_info; }
};
} // namespace srsran
#endif // SRSRAN_RADIO_DUMMY_H

@ -113,11 +113,9 @@ public:
protected: protected:
// Common variables needed/provided by parent class // Common variables needed/provided by parent class
srslog::basic_logger& logger;
srsran::timer_handler* timers = nullptr; srsran::timer_handler* timers = nullptr;
uint32_t lcid = 0; uint32_t lcid = 0;
rlc_config_t cfg = {}; rlc_config_t cfg = {};
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
@ -130,13 +128,13 @@ protected:
/******************************************************* /*******************************************************
* RLC AM TX entity * RLC AM TX entity
* This class is used for common code between the * This class is used for common code between the
* LTE and NR TX entitites * LTE and NR TX entities
*******************************************************/ *******************************************************/
public: public:
class rlc_am_base_tx class rlc_am_base_tx
{ {
public: public:
explicit rlc_am_base_tx(srslog::basic_logger* logger_) : logger(logger_) {} explicit rlc_am_base_tx(srslog::basic_logger& logger_) : logger(logger_) {}
virtual ~rlc_am_base_tx() = default; virtual ~rlc_am_base_tx() = default;
virtual bool configure(const rlc_config_t& cfg_) = 0; virtual bool configure(const rlc_config_t& cfg_) = 0;
@ -157,7 +155,7 @@ public:
bool tx_enabled = false; bool tx_enabled = false;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
srslog::basic_logger* logger; srslog::basic_logger& logger;
std::string rb_name; std::string rb_name;
bsr_callback_t bsr_callback; bsr_callback_t bsr_callback;
@ -172,12 +170,12 @@ public:
/******************************************************* /*******************************************************
* RLC AM RX entity * RLC AM RX entity
* This class is used for common code between the * This class is used for common code between the
* LTE and NR RX entitites * LTE and NR RX entities
*******************************************************/ *******************************************************/
class rlc_am_base_rx class rlc_am_base_rx
{ {
public: public:
explicit rlc_am_base_rx(rlc_am* parent_, srslog::basic_logger* logger_) : parent(parent_), logger(logger_) {} explicit rlc_am_base_rx(rlc_am* parent_, srslog::basic_logger& logger_) : parent(parent_), logger(logger_) {}
virtual ~rlc_am_base_rx() = default; virtual ~rlc_am_base_rx() = default;
virtual bool configure(const rlc_config_t& cfg_) = 0; virtual bool configure(const rlc_config_t& cfg_) = 0;
@ -189,9 +187,10 @@ public:
void write_pdu(uint8_t* payload, uint32_t nof_bytes); void write_pdu(uint8_t* payload, uint32_t nof_bytes);
srslog::basic_logger* logger = nullptr; srslog::basic_logger& logger;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
rlc_am* parent = nullptr; rlc_am* parent = nullptr;
std::string rb_name;
protected: protected:
std::atomic<bool> do_status = {false}; // light-weight access from Tx entity std::atomic<bool> do_status = {false}; // light-weight access from Tx entity

@ -65,19 +65,51 @@ uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_pdu_segment(uint8_t* payload);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi);
std::string std::string
rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info<rlc_amd_pdu_header_t> >& info_queue); rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info<rlc_amd_pdu_header_t> >& info_queue);
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);
bool rlc_am_start_aligned(const uint8_t fi); template <typename... Args>
bool rlc_am_end_aligned(const uint8_t fi); void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch,
bool rlc_am_is_unaligned(const uint8_t fi); const std::string& rb_name,
bool rlc_am_not_start_aligned(const uint8_t fi); const char* fmt_str,
const rlc_amd_pdu_header_t& header,
Args&&... args)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer,
"{}: [{}, RF={}, P={}, FI={}, SN={}, LSF={}, SO={}, N_li={}",
rb_name,
rlc_dc_field_text[header.dc],
(header.rf ? "1" : "0"),
(header.p ? "1" : "0"),
(header.fi ? "1" : "0"),
header.sn,
(header.lsf ? "1" : "0"),
header.so,
header.N_li);
if (header.N_li > 0) {
fmt::format_to(buffer, " ({}", header.li[0]);
for (uint32_t i = 1; i < header.N_li; ++i) {
fmt::format_to(buffer, ", {}", header.li[i]);
}
fmt::format_to(buffer, ")");
}
fmt::format_to(buffer, "]");
log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer));
}
/**
* Logs Status PDU into provided log channel, using fmt_str as format string
*/
template <typename... Args> template <typename... Args>
void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch, void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
const std::string& rb_name,
const char* fmt_str, const char* fmt_str,
rlc_status_pdu_t* status, rlc_status_pdu_t* status,
Args&&... args) Args&&... args)
@ -86,7 +118,7 @@ void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
return; return;
} }
fmt::memory_buffer buffer; fmt::memory_buffer buffer;
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->N_nack); fmt::format_to(buffer, "{}: ACK_SN = {}, N_nack = {}", rb_name, status->ack_sn, status->N_nack);
if (status->N_nack > 0) { if (status->N_nack > 0) {
fmt::format_to(buffer, ", NACK_SN = "); fmt::format_to(buffer, ", NACK_SN = ");
for (uint32_t i = 0; i < status->N_nack; ++i) { for (uint32_t i = 0; i < status->N_nack; ++i) {
@ -100,7 +132,6 @@ void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
} }
log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer)); log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer));
} }
} // namespace srsran } // namespace srsran
#endif // SRSRAN_RLC_AM_LTE_PACKING_H #endif // SRSRAN_RLC_AM_LTE_PACKING_H

@ -46,7 +46,7 @@ class rlc_am_nr_rx;
/**************************************************************************** /****************************************************************************
* Tx state variables * Tx state variables
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
***************************************************************************/ ***************************************************************************/
struct rlc_am_nr_tx_state_t { struct rlc_am_nr_tx_state_t {
/* /*
@ -79,6 +79,21 @@ struct rlc_am_nr_tx_state_t {
uint32_t byte_without_poll; uint32_t byte_without_poll;
}; };
struct rlc_amd_tx_pdu_nr {
const uint32_t rlc_sn = INVALID_RLC_SN;
const uint32_t pdcp_sn = INVALID_RLC_SN;
rlc_am_nr_pdu_header_t header = {};
unique_byte_buffer_t buf = nullptr;
uint32_t retx_count = 0;
struct pdu_segment {
uint32_t so = 0;
uint32_t retx_count = 0;
uint32_t payload_len = 0;
};
std::list<pdu_segment> segment_list;
explicit rlc_amd_tx_pdu_nr(uint32_t sn) : rlc_sn(sn) {}
};
class rlc_am_nr_tx : public rlc_am::rlc_am_base_tx class rlc_am_nr_tx : public rlc_am::rlc_am_base_tx
{ {
public: public:
@ -94,19 +109,29 @@ public:
bool sdu_queue_is_full() final; bool sdu_queue_is_full() final;
void reestablish() final; void reestablish() final;
int write_sdu(unique_byte_buffer_t sdu); int write_sdu(unique_byte_buffer_t sdu);
void empty_queue() final; void empty_queue() final;
// Data PDU helpers
int build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
rlc_amd_tx_pdu_nr& tx_pdu,
uint8_t* payload,
uint32_t nof_bytes);
int build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes);
// Buffer State
bool has_data() final; bool has_data() final;
uint32_t get_buffer_state() final; uint32_t get_buffer_state() final;
void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final; void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final;
// Status PDU
bool do_status(); bool do_status();
uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes); uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes);
// Polling
uint8_t get_pdu_poll(); uint8_t get_pdu_poll();
int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes);
void stop() final; void stop() final;
bool inside_tx_window(uint32_t sn); bool inside_tx_window(uint32_t sn);
@ -120,19 +145,25 @@ private:
/**************************************************************************** /****************************************************************************
* Configurable parameters * Configurable parameters
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.4 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.4
***************************************************************************/ ***************************************************************************/
rlc_am_nr_config_t cfg = {}; rlc_am_nr_config_t cfg = {};
/**************************************************************************** /****************************************************************************
* Tx state variables * Tx state variables
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
***************************************************************************/ ***************************************************************************/
struct rlc_am_nr_tx_state_t st = {}; struct rlc_am_nr_tx_state_t st = {};
using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu<rlc_am_nr_pdu_header_t>;
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window; rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
// Queues and buffers
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
rlc_amd_tx_sdu_nr_t sdu_under_segmentation;
// Helper constants
uint32_t min_hdr_size = 2;
uint32_t so_size = 2;
uint32_t max_hdr_size = 4;
public: public:
// Getters/Setters // Getters/Setters
@ -142,8 +173,8 @@ public:
}; };
/**************************************************************************** /****************************************************************************
* RX State Variables * State Variables
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
***************************************************************************/ ***************************************************************************/
struct rlc_am_nr_rx_state_t { struct rlc_am_nr_rx_state_t {
/* /*
@ -190,9 +221,11 @@ public:
uint32_t get_status_pdu_length(); uint32_t get_status_pdu_length();
// Data handling methods // Data handling methods
void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header); int handle_full_data_sdu(const rlc_am_nr_pdu_header_t& header, const uint8_t* payload, uint32_t nof_bytes);
int handle_segment_data_sdu(const rlc_am_nr_pdu_header_t& header, const uint8_t* payload, uint32_t nof_bytes);
bool inside_rx_window(uint32_t sn); bool inside_rx_window(uint32_t sn);
void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu); void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu);
bool have_all_segments_been_received(const std::list<rlc_amd_rx_pdu_nr>& segment_list);
// Metrics // Metrics
uint32_t get_sdu_rx_latency_ms() final; uint32_t get_sdu_rx_latency_ms() final;
@ -220,20 +253,20 @@ private:
/**************************************************************************** /****************************************************************************
* Rx timers * Rx timers
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.3 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.3
***************************************************************************/ ***************************************************************************/
srsran::timer_handler::unique_timer status_prohibit_timer; srsran::timer_handler::unique_timer status_prohibit_timer;
srsran::timer_handler::unique_timer reassembly_timer; srsran::timer_handler::unique_timer reassembly_timer;
/**************************************************************************** /****************************************************************************
* Configurable parameters * Configurable parameters
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.4 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.4
***************************************************************************/ ***************************************************************************/
rlc_am_nr_config_t cfg = {}; rlc_am_nr_config_t cfg = {};
/**************************************************************************** /****************************************************************************
* Tx state variables * Tx state variables
* Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 * Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
***************************************************************************/ ***************************************************************************/
struct rlc_am_nr_rx_state_t st = {}; struct rlc_am_nr_rx_state_t st = {};

@ -27,6 +27,8 @@
namespace srsran { namespace srsran {
const uint32_t INVALID_RLC_SN = 0xFFFFFFFF;
///< AM NR PDU header ///< AM NR PDU header
struct rlc_am_nr_pdu_header_t { struct rlc_am_nr_pdu_header_t {
rlc_am_nr_pdu_header_t() = default; rlc_am_nr_pdu_header_t() = default;
@ -69,6 +71,14 @@ struct rlc_amd_rx_sdu_nr_t {
explicit rlc_amd_rx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} explicit rlc_amd_rx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
}; };
struct rlc_amd_tx_sdu_nr_t {
uint32_t rlc_sn = INVALID_RLC_SN;
unique_byte_buffer_t buf;
rlc_amd_tx_sdu_nr_t() = default;
explicit rlc_amd_tx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
};
///< AM NR Status PDU header (perhaps merge with LTE version) ///< AM NR Status PDU header (perhaps merge with LTE version)
typedef struct { typedef struct {
rlc_am_nr_control_pdu_type_t cpt; rlc_am_nr_control_pdu_type_t cpt;
@ -91,6 +101,7 @@ uint32_t rlc_am_nr_read_data_pdu_header(const uint8_t* payload,
const rlc_am_nr_sn_size_t sn_size, const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_pdu_header_t* header); rlc_am_nr_pdu_header_t* header);
uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, uint8_t* payload);
uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu); uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu);
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header); uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header);

@ -43,6 +43,16 @@ namespace srsran {
#define RLC_MAX_SDU_SIZE ((1 << 11) - 1) // Length of LI field is 11bits #define RLC_MAX_SDU_SIZE ((1 << 11) - 1) // Length of LI field is 11bits
#define RLC_AM_MIN_DATA_PDU_SIZE (3) // AMD PDU with 10 bit SN (length of LI field is 11 bits) (No LI) #define RLC_AM_MIN_DATA_PDU_SIZE (3) // AMD PDU with 10 bit SN (length of LI field is 11 bits) (No LI)
#define RlcDebug(fmt, ...) logger.debug("%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcInfo(fmt, ...) logger.info("%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcWarning(fmt, ...) logger.warning("%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcError(fmt, ...) logger.error("%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcHexDebug(msg, bytes, fmt, ...) logger.debug(msg, bytes, "%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcHexInfo(msg, bytes, fmt, ...) logger.info(msg, bytes, "%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcHexWarning(msg, bytes, fmt, ...) logger.warning(msg, bytes, "%s: " fmt, rb_name, ##__VA_ARGS__)
#define RlcHexError(msg, bytes, fmt, ...) logger.error(msg, bytes, "%s: " fmt, rb_name, ##__VA_ARGS__)
typedef enum { typedef enum {
RLC_FI_FIELD_START_AND_END_ALIGNED = 0, RLC_FI_FIELD_START_AND_END_ALIGNED = 0,
RLC_FI_FIELD_NOT_END_ALIGNED, RLC_FI_FIELD_NOT_END_ALIGNED,
@ -197,6 +207,7 @@ typedef std::function<void(uint32_t, uint32_t, uint32_t)> bsr_callback_t;
class rlc_common class rlc_common
{ {
public: public:
explicit rlc_common(srslog::basic_logger& logger_) : logger(logger_) {}
virtual ~rlc_common() = default; virtual ~rlc_common() = default;
virtual bool configure(const rlc_config_t& cnfg) = 0; virtual bool configure(const rlc_config_t& cnfg) = 0;
virtual void stop() = 0; virtual void stop() = 0;
@ -274,6 +285,10 @@ public:
void* operator new(size_t sz) { return allocate_rlc_bearer(sz); } void* operator new(size_t sz) { return allocate_rlc_bearer(sz); }
void operator delete(void* p) { return deallocate_rlc_bearer(p); } void operator delete(void* p) { return deallocate_rlc_bearer(p); }
protected:
std::string rb_name = {};
srslog::basic_logger& logger;
private: private:
bool suspended = false; bool suspended = false;

@ -71,7 +71,6 @@ public:
private: private:
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger;
uint32_t lcid = 0; uint32_t lcid = 0;
srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr;
srsue::rrc_interface_rlc* rrc = nullptr; srsue::rrc_interface_rlc* rrc = nullptr;

@ -163,14 +163,12 @@ protected:
}; };
// Common variables needed by parent class // Common variables needed by parent class
srsue::rrc_interface_rlc* rrc = nullptr; srsue::rrc_interface_rlc* rrc = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr;
srslog::basic_logger& logger;
srsran::timer_handler* timers = nullptr; srsran::timer_handler* timers = nullptr;
uint32_t lcid = 0; uint32_t lcid = 0;
rlc_config_t cfg = {}; rlc_config_t cfg = {};
std::string rb_name; byte_buffer_pool* pool = nullptr;
byte_buffer_pool* pool = nullptr;
std::string get_rb_name(srsue::rrc_interface_rlc* rrc, uint32_t lcid, bool is_mrb); std::string get_rb_name(srsue::rrc_interface_rlc* rrc, uint32_t lcid, bool is_mrb);
// Rx and Tx objects // Rx and Tx objects

@ -1421,10 +1421,15 @@ SRSASN_CODE ext_groups_unpacker_guard::unpack(cbit_ref& bref)
Open Field Open Field
*********************/ *********************/
varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align_) varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align_) :
buffer_ptr(srsran::make_buffer_pool_obj<byte_array_t>())
{ {
if (buffer_ptr == nullptr) {
// failed to allocate from global byte buffer pool. Fallback to malloc
buffer_ptr = std::unique_ptr<byte_array_t>(new byte_array_t());
}
brefstart = bref; brefstart = bref;
bref = bit_ref(&buffer[0], sizeof(buffer)); bref = bit_ref(buffer_ptr->data(), buffer_ptr->size());
bref_tracker = &bref; bref_tracker = &bref;
align = align_; align = align_;
} }
@ -1432,16 +1437,15 @@ varlength_field_pack_guard::varlength_field_pack_guard(bit_ref& bref, bool align
varlength_field_pack_guard::~varlength_field_pack_guard() varlength_field_pack_guard::~varlength_field_pack_guard()
{ {
// fill the spare bits // fill the spare bits
const bit_ref bref0 = bit_ref(&buffer[0], sizeof(buffer)); uint32_t leftover = 7 - ((bref_tracker->distance() - (uint32_t)1) % (uint32_t)8);
uint32_t leftover = 7 - ((bref_tracker->distance(bref0) - (uint32_t)1) % (uint32_t)8);
bref_tracker->pack(0, leftover); bref_tracker->pack(0, leftover);
// check how many bytes were written in total // check how many bytes were written in total
uint32_t nof_bytes = bref_tracker->distance(bref0) / (uint32_t)8; uint32_t nof_bytes = bref_tracker->distance() / (uint32_t)8;
if (nof_bytes > sizeof(buffer)) { if (nof_bytes > buffer_ptr->size()) {
log_error("The packed variable sized field is too long for the reserved buffer (%zd > %zd)", log_error("The packed variable sized field is too long for the reserved buffer (%zd > %zd)",
(size_t)nof_bytes, (size_t)nof_bytes,
sizeof(buffer)); buffer_ptr->size());
} }
// go back in time to pack length // go back in time to pack length
@ -1449,7 +1453,7 @@ varlength_field_pack_guard::~varlength_field_pack_guard()
// pack encoded bytes // pack encoded bytes
for (uint32_t i = 0; i < nof_bytes; ++i) { for (uint32_t i = 0; i < nof_bytes; ++i) {
brefstart.pack(buffer[i], 8); brefstart.pack((*buffer_ptr)[i], 8);
} }
*bref_tracker = brefstart; *bref_tracker = brefstart;
} }
@ -1561,4 +1565,49 @@ std::string json_writer::to_string() const
return std::string(buffer.data(), buffer.size()); return std::string(buffer.data(), buffer.size());
} }
/************************
General Layer Types
************************/
uint32_t detail::base_empty_obj_set::idx_to_id(uint32_t idx)
{
asn1::log_error("object set is empty\n");
return 0;
}
bool detail::base_empty_obj_set::is_id_valid(const uint32_t& id)
{
asn1::log_error("object set is empty\n");
return false;
}
crit_e detail::base_empty_obj_set::get_crit(const uint32_t& id)
{
return {};
}
presence_e detail::base_empty_obj_set::get_presence(const uint32_t& id)
{
return {};
}
void detail::empty_obj_set_item_c::to_json(json_writer& j) const
{
j.start_obj();
j.end_obj();
}
SRSASN_CODE detail::empty_obj_set_item_c::pack(bit_ref& bref) const
{
varlength_field_pack_guard varlen_scope(bref, true);
return SRSASN_SUCCESS;
}
SRSASN_CODE detail::empty_obj_set_item_c::unpack(cbit_ref& bref)
{
varlength_field_unpack_guard varlen_scope(bref, true);
return SRSASN_SUCCESS;
}
const char* detail::empty_obj_set_item_c::types_opts::to_string() const
{
log_error("The enum value=0 of type protocol_ies_empty_o::value_c::types is not valid.");
return "";
}
} // namespace asn1 } // namespace asn1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -180,7 +180,7 @@ srsran::pdcp_config_t make_nr_srb_pdcp_config_t(const uint8_t bearer_id, bool is
pdcp_t_reordering_t::ms500, pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity, pdcp_discard_timer_t::infinity,
false, false,
srsran_rat_t::lte); srsran_rat_t::nr);
return cfg; return cfg;
} }
@ -343,43 +343,103 @@ bool make_phy_tdd_cfg(const tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common,
srsran_duplex_config_nr.tdd.pattern1.nof_dl_symbols = tdd_ul_dl_cfg_common.pattern1.nrof_dl_symbols; srsran_duplex_config_nr.tdd.pattern1.nof_dl_symbols = tdd_ul_dl_cfg_common.pattern1.nrof_dl_symbols;
srsran_duplex_config_nr.tdd.pattern1.nof_ul_slots = tdd_ul_dl_cfg_common.pattern1.nrof_ul_slots; srsran_duplex_config_nr.tdd.pattern1.nof_ul_slots = tdd_ul_dl_cfg_common.pattern1.nrof_ul_slots;
srsran_duplex_config_nr.tdd.pattern1.nof_ul_symbols = tdd_ul_dl_cfg_common.pattern1.nrof_ul_symbols; srsran_duplex_config_nr.tdd.pattern1.nof_ul_symbols = tdd_ul_dl_cfg_common.pattern1.nrof_ul_symbols;
if (tdd_ul_dl_cfg_common.pattern2_present) {
switch (tdd_ul_dl_cfg_common.pattern2.dl_ul_tx_periodicity) {
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 1;
break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 2;
break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms5:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 5;
break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 10;
break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1p25:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms0p5:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms0p625:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2p5:
default:
asn1::log_warning("Invalid option for pattern2 dl_ul_tx_periodicity_opts %s",
tdd_ul_dl_cfg_common.pattern2.dl_ul_tx_periodicity.to_string());
return false;
}
srsran_duplex_config_nr.tdd.pattern2.nof_dl_slots = tdd_ul_dl_cfg_common.pattern2.nrof_dl_slots;
srsran_duplex_config_nr.tdd.pattern2.nof_dl_symbols = tdd_ul_dl_cfg_common.pattern2.nrof_dl_symbols;
srsran_duplex_config_nr.tdd.pattern2.nof_ul_slots = tdd_ul_dl_cfg_common.pattern2.nrof_ul_slots;
srsran_duplex_config_nr.tdd.pattern2.nof_ul_symbols = tdd_ul_dl_cfg_common.pattern2.nrof_ul_symbols;
}
// Copy and return struct // Copy and return struct
*in_srsran_duplex_config_nr = srsran_duplex_config_nr; *in_srsran_duplex_config_nr = srsran_duplex_config_nr;
if (not tdd_ul_dl_cfg_common.pattern2_present) { return true;
}
bool make_phy_tdd_cfg(const srsran_duplex_config_nr_t& srsran_duplex_config_nr,
srsran_subcarrier_spacing_t scs,
asn1::rrc_nr::tdd_ul_dl_cfg_common_s* tdd_ul_dl_cfg_common)
{
if (srsran_duplex_config_nr.mode == SRSRAN_DUPLEX_MODE_FDD) {
return true; return true;
} }
tdd_ul_dl_cfg_common->ref_subcarrier_spacing.value = (asn1::rrc_nr::subcarrier_spacing_e::options)scs;
switch (tdd_ul_dl_cfg_common.pattern2.dl_ul_tx_periodicity) { switch (srsran_duplex_config_nr.tdd.pattern1.period_ms) {
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1: case 1:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 1; tdd_ul_dl_cfg_common->pattern1.dl_ul_tx_periodicity = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1;
break; break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2: case 2:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 2; tdd_ul_dl_cfg_common->pattern1.dl_ul_tx_periodicity = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2;
break; break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms5: case 5:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 5; tdd_ul_dl_cfg_common->pattern1.dl_ul_tx_periodicity = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms5;
break; break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10: case 10:
srsran_duplex_config_nr.tdd.pattern2.period_ms = 10; tdd_ul_dl_cfg_common->pattern1.dl_ul_tx_periodicity = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10;
break; break;
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1p25:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms0p5:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms0p625:
case tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2p5:
default: default:
asn1::log_warning("Invalid option for pattern2 dl_ul_tx_periodicity_opts %s", asn1::log_warning("Invalid option for dl_ul_tx_periodicity_opts %d",
tdd_ul_dl_cfg_common.pattern2.dl_ul_tx_periodicity.to_string()); srsran_duplex_config_nr.tdd.pattern1.period_ms);
return false; return false;
} }
tdd_ul_dl_cfg_common->pattern1.nrof_dl_slots = srsran_duplex_config_nr.tdd.pattern1.nof_dl_slots;
tdd_ul_dl_cfg_common->pattern1.nrof_dl_symbols = srsran_duplex_config_nr.tdd.pattern1.nof_dl_symbols;
tdd_ul_dl_cfg_common->pattern1.nrof_ul_slots = srsran_duplex_config_nr.tdd.pattern1.nof_ul_slots;
tdd_ul_dl_cfg_common->pattern1.nrof_ul_symbols = srsran_duplex_config_nr.tdd.pattern1.nof_ul_symbols;
srsran_duplex_config_nr.tdd.pattern2.nof_dl_slots = tdd_ul_dl_cfg_common.pattern2.nrof_dl_slots; if (srsran_duplex_config_nr.tdd.pattern2.period_ms == 0) {
srsran_duplex_config_nr.tdd.pattern2.nof_dl_symbols = tdd_ul_dl_cfg_common.pattern2.nrof_dl_symbols; return true;
srsran_duplex_config_nr.tdd.pattern2.nof_ul_slots = tdd_ul_dl_cfg_common.pattern2.nrof_ul_slots; }
srsran_duplex_config_nr.tdd.pattern2.nof_ul_symbols = tdd_ul_dl_cfg_common.pattern2.nrof_ul_symbols;
// Copy and return struct tdd_ul_dl_cfg_common->pattern2_present = true;
*in_srsran_duplex_config_nr = srsran_duplex_config_nr; switch (srsran_duplex_config_nr.tdd.pattern2.period_ms) {
case 1:
tdd_ul_dl_cfg_common->pattern2.dl_ul_tx_periodicity.value = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms1;
break;
case 2:
tdd_ul_dl_cfg_common->pattern2.dl_ul_tx_periodicity.value = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms2;
break;
case 5:
tdd_ul_dl_cfg_common->pattern2.dl_ul_tx_periodicity.value = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms5;
break;
case 10:
tdd_ul_dl_cfg_common->pattern2.dl_ul_tx_periodicity.value = tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10;
break;
default:
asn1::log_warning("Invalid option for pattern2 dl_ul_tx_periodicity_opts %d",
srsran_duplex_config_nr.tdd.pattern2.period_ms);
return false;
}
tdd_ul_dl_cfg_common->pattern2.nrof_dl_slots = srsran_duplex_config_nr.tdd.pattern2.nof_dl_slots;
tdd_ul_dl_cfg_common->pattern2.nrof_dl_symbols = srsran_duplex_config_nr.tdd.pattern2.nof_dl_symbols;
tdd_ul_dl_cfg_common->pattern2.nrof_ul_slots = srsran_duplex_config_nr.tdd.pattern2.nof_ul_slots;
tdd_ul_dl_cfg_common->pattern2.nrof_ul_symbols = srsran_duplex_config_nr.tdd.pattern2.nof_ul_symbols;
return true; return true;
} }
@ -1523,7 +1583,7 @@ bool make_phy_mib(const asn1::rrc_nr::mib_s& mib_cfg, srsran_mib_nr_t* mib)
{ {
mib->sfn = 0; mib->sfn = 0;
mib->ssb_idx = 0; mib->ssb_idx = 0;
mib->hrf = 0; mib->hrf = false;
mib->scs_common = mib->scs_common =
mib_cfg.sub_carrier_spacing_common.value == asn1::rrc_nr::mib_s::sub_carrier_spacing_common_opts::scs15or60 mib_cfg.sub_carrier_spacing_common.value == asn1::rrc_nr::mib_s::sub_carrier_spacing_common_opts::scs15or60
? srsran_subcarrier_spacing_15kHz ? srsran_subcarrier_spacing_15kHz
@ -1539,30 +1599,25 @@ bool make_phy_mib(const asn1::rrc_nr::mib_s& mib_cfg, srsran_mib_nr_t* mib)
bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl) bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl)
{ {
if (serv_cell.csi_meas_cfg_present and if (serv_cell.csi_meas_cfg_present and serv_cell.csi_meas_cfg.is_setup()) {
serv_cell.csi_meas_cfg.type().value ==
setup_release_c< ::asn1::rrc_nr::csi_meas_cfg_s>::types_opts::options::setup) {
auto& setup = serv_cell.csi_meas_cfg.setup(); auto& setup = serv_cell.csi_meas_cfg.setup();
// Configure NZP-CSI // Configure NZP-CSI
if (setup.nzp_csi_rs_res_set_to_add_mod_list_present) { for (auto& nzp_set : setup.nzp_csi_rs_res_set_to_add_mod_list) {
for (auto& nzp_set : setup.nzp_csi_rs_res_set_to_add_mod_list) { auto& uecfg_set = sch_hl->nzp_csi_rs_sets[nzp_set.nzp_csi_res_set_id];
auto& uecfg_set = sch_hl->nzp_csi_rs_sets[nzp_set.nzp_csi_res_set_id]; uecfg_set.trs_info = nzp_set.trs_info_present;
uecfg_set.trs_info = nzp_set.trs_info_present; uecfg_set.count = nzp_set.nzp_csi_rs_res.size();
uecfg_set.count = nzp_set.nzp_csi_rs_res.size(); uint32_t count = 0;
uint32_t count = 0; for (uint8_t nzp_rs_idx : nzp_set.nzp_csi_rs_res) {
for (uint8_t nzp_rs_idx : nzp_set.nzp_csi_rs_res) { auto& res = uecfg_set.data[count++];
auto& res = uecfg_set.data[count++]; if (not srsran::make_phy_nzp_csi_rs_resource(setup.nzp_csi_rs_res_to_add_mod_list[nzp_rs_idx], &res)) {
if (not srsran::make_phy_nzp_csi_rs_resource(setup.nzp_csi_rs_res_to_add_mod_list[nzp_rs_idx], &res)) { return false;
return false;
}
} }
} }
} }
} }
if (serv_cell.init_dl_bwp.pdsch_cfg_present and if (serv_cell.init_dl_bwp.pdsch_cfg_present and serv_cell.init_dl_bwp.pdsch_cfg.is_setup()) {
serv_cell.init_dl_bwp.pdsch_cfg.type() == setup_release_c<pdsch_cfg_s>::types_opts::setup) {
const auto& setup = serv_cell.init_dl_bwp.pdsch_cfg.setup(); const auto& setup = serv_cell.init_dl_bwp.pdsch_cfg.setup();
if (setup.p_zp_csi_rs_res_set_present) { if (setup.p_zp_csi_rs_res_set_present) {
auto& setup_set = setup.p_zp_csi_rs_res_set.setup(); auto& setup_set = setup.p_zp_csi_rs_res_set.setup();
@ -1582,18 +1637,14 @@ bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_
bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl) bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl)
{ {
if (serv_cell.csi_meas_cfg_present and if (serv_cell.csi_meas_cfg_present and serv_cell.csi_meas_cfg.is_setup()) {
serv_cell.csi_meas_cfg.type().value ==
setup_release_c< ::asn1::rrc_nr::csi_meas_cfg_s>::types_opts::options::setup) {
auto& setup = serv_cell.csi_meas_cfg.setup(); auto& setup = serv_cell.csi_meas_cfg.setup();
// Configure CSI-Report // Configure CSI-Report
if (setup.csi_report_cfg_to_add_mod_list_present) { for (uint32_t i = 0; i < setup.csi_report_cfg_to_add_mod_list.size(); ++i) {
for (uint32_t i = 0; i < setup.csi_report_cfg_to_add_mod_list.size(); ++i) { const auto& csi_rep = setup.csi_report_cfg_to_add_mod_list[i];
const auto& csi_rep = setup.csi_report_cfg_to_add_mod_list[i]; if (not make_phy_csi_report(csi_rep, &csi_hl->reports[i])) {
if (not make_phy_csi_report(csi_rep, &csi_hl->reports[i])) { return false;
return false;
}
} }
} }
} }
@ -1615,18 +1666,14 @@ bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_
bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch) bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch)
{ {
if (pdcch_cfg.ctrl_res_set_to_add_mod_list_present) { for (const ctrl_res_set_s& coreset : pdcch_cfg.ctrl_res_set_to_add_mod_list) {
for (const ctrl_res_set_s& coreset : pdcch_cfg.ctrl_res_set_to_add_mod_list) { pdcch->coreset_present[coreset.ctrl_res_set_id] = true;
pdcch->coreset_present[coreset.ctrl_res_set_id] = true; make_phy_coreset_cfg(coreset, &pdcch->coreset[coreset.ctrl_res_set_id]);
make_phy_coreset_cfg(coreset, &pdcch->coreset[coreset.ctrl_res_set_id]);
}
} }
if (pdcch_cfg.search_spaces_to_add_mod_list_present) { for (const search_space_s& ss : pdcch_cfg.search_spaces_to_add_mod_list) {
for (const search_space_s& ss : pdcch_cfg.search_spaces_to_add_mod_list) { pdcch->search_space_present[ss.search_space_id] = true;
pdcch->search_space_present[ss.search_space_id] = true; make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]);
make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]);
}
} }
return true; return true;
} }
@ -1637,14 +1684,12 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg
pdcch->coreset_present[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id] = true; pdcch->coreset_present[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id] = true;
make_phy_coreset_cfg(pdcch_cfg.common_ctrl_res_set, &pdcch->coreset[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id]); make_phy_coreset_cfg(pdcch_cfg.common_ctrl_res_set, &pdcch->coreset[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id]);
} }
if (pdcch_cfg.common_search_space_list_present) { for (const search_space_s& ss : pdcch_cfg.common_search_space_list) {
for (const search_space_s& ss : pdcch_cfg.common_search_space_list) { pdcch->search_space_present[ss.search_space_id] = true;
pdcch->search_space_present[ss.search_space_id] = true; make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]);
make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]); if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) {
if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) { pdcch->ra_search_space_present = true;
pdcch->ra_search_space_present = true; pdcch->ra_search_space = pdcch->search_space[ss.search_space_id];
pdcch->ra_search_space = pdcch->search_space[ss.search_space_id];
}
} }
} }
} }

File diff suppressed because it is too large Load Diff

@ -35,21 +35,21 @@ template <>
uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o> >( uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o> >(
const protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o>& obj) const protocol_ie_single_container_s<erab_to_be_setup_item_ctxt_su_req_ies_o>& obj)
{ {
return obj.value.erab_to_be_setup_item_ctxt_su_req().erab_id; return obj->erab_to_be_setup_item_ctxt_su_req().erab_id;
} }
template <> template <>
uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_setup_item_bearer_su_req_ies_o> >( uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_setup_item_bearer_su_req_ies_o> >(
const protocol_ie_single_container_s<erab_to_be_setup_item_bearer_su_req_ies_o>& obj) const protocol_ie_single_container_s<erab_to_be_setup_item_bearer_su_req_ies_o>& obj)
{ {
return obj.value.erab_to_be_setup_item_bearer_su_req().erab_id; return obj->erab_to_be_setup_item_bearer_su_req().erab_id;
} }
template <> template <>
uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_modified_item_bearer_mod_req_ies_o> >( uint32_t get_obj_id<protocol_ie_single_container_s<erab_to_be_modified_item_bearer_mod_req_ies_o> >(
const protocol_ie_single_container_s<erab_to_be_modified_item_bearer_mod_req_ies_o>& obj) const protocol_ie_single_container_s<erab_to_be_modified_item_bearer_mod_req_ies_o>& obj)
{ {
return obj.value.erab_to_be_modified_item_bearer_mod_req().erab_id; return obj->erab_to_be_modified_item_bearer_mod_req().erab_id;
} }
} // namespace s1ap } // namespace s1ap

@ -175,7 +175,7 @@ uint32_t srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t
return find_lower_bound_abs_freq_ssb(band, scs, freq_point_a_hz + coreset0_offset_hz); return find_lower_bound_abs_freq_ssb(band, scs, freq_point_a_hz + coreset0_offset_hz);
} }
srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) const srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs)
{ {
// Look for the given band and SCS // Look for the given band and SCS
for (const nr_band_ss_raster& ss_raster : nr_band_ss_raster_table) { for (const nr_band_ss_raster& ss_raster : nr_band_ss_raster_table) {

@ -47,6 +47,7 @@
#define ALGO_EPS_DISTINGUISHER_UP_ENC_ALG 0x05 #define ALGO_EPS_DISTINGUISHER_UP_ENC_ALG 0x05
#define ALGO_EPS_DISTINGUISHER_UP_INT_ALG 0x06 #define ALGO_EPS_DISTINGUISHER_UP_INT_ALG 0x06
#define FC_5G_K_GNB_STAR_DERIVATION 0x70
#define FC_5G_ALGORITHM_KEY_DERIVATION 0x69 #define FC_5G_ALGORITHM_KEY_DERIVATION 0x69
#define FC_5G_KAUSF_DERIVATION 0x6A #define FC_5G_KAUSF_DERIVATION 0x6A
#define FC_5G_RES_STAR_DERIVATION 0x6B #define FC_5G_RES_STAR_DERIVATION 0x6B
@ -228,8 +229,27 @@ uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count_
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
// Generate k_enb* according to TS 33.401 Appendix A.5
uint8_t uint8_t
security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci_, const uint32_t earfcn_, uint8_t* k_enb_star) security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci_, const uint32_t earfcn_, uint8_t* k_enb_star)
{
return security_generate_k_nb_star_common(FC_EPS_K_ENB_STAR_DERIVATION, k_enb, pci_, earfcn_, k_enb_star);
}
// Generate k_gnb* according to TS 33.501 Appendix A.11
uint8_t
security_generate_k_gnb_star(const uint8_t* k_gnb, const uint32_t pci_, const uint32_t dl_arfcn_, uint8_t* k_gnb_star)
{
return security_generate_k_nb_star_common(FC_5G_K_GNB_STAR_DERIVATION, k_gnb, pci_, dl_arfcn_, k_gnb_star);
}
uint8_t security_generate_k_nb_star_common(uint8_t fc,
const uint8_t* k_enb,
const uint32_t pci_,
const uint32_t earfcn_,
uint8_t* k_enb_star)
{ {
if (k_enb == NULL || k_enb_star == NULL) { if (k_enb == NULL || k_enb_star == NULL) {
log_error("Invalid inputs"); log_error("Invalid inputs");
@ -244,13 +264,20 @@ security_generate_k_enb_star(const uint8_t* k_enb, const uint32_t pci_, const ui
pci[0] = (pci_ >> 8) & 0xFF; pci[0] = (pci_ >> 8) & 0xFF;
pci[1] = pci_ & 0xFF; pci[1] = pci_ & 0xFF;
// EARFCN // ARFCN, can be two or three bytes
std::vector<uint8_t> earfcn; std::vector<uint8_t> earfcn;
earfcn.resize(2); if (earfcn_ < pow(2, 16)) {
earfcn[0] = (earfcn_ >> 8) & 0xFF; earfcn.resize(2);
earfcn[1] = earfcn_ & 0xFF; earfcn[0] = (earfcn_ >> 8) & 0xFF;
earfcn[1] = earfcn_ & 0xFF;
if (kdf_common(FC_EPS_K_ENB_STAR_DERIVATION, key, pci, earfcn, k_enb_star) != SRSRAN_SUCCESS) { } else if (earfcn_ < pow(2, 24)) {
earfcn.resize(3);
earfcn[0] = (earfcn_ >> 16) & 0xFF;
earfcn[1] = (earfcn_ >> 8) & 0xFF;
earfcn[2] = earfcn_ & 0xFF;
}
if (kdf_common(fc, key, pci, earfcn, k_enb_star) != SRSRAN_SUCCESS) {
log_error("Failed to run kdf_common"); log_error("Failed to run kdf_common");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }

@ -173,7 +173,7 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu, int upper_sn)
// If the bearer is mapped to RLC AM, save TX_COUNT and a copy of the PDU. // If the bearer is mapped to RLC AM, save TX_COUNT and a copy of the PDU.
// This will be used for reestablishment, where unack'ed PDUs will be re-transmitted. // This will be used for reestablishment, where unack'ed PDUs will be re-transmitted.
// PDUs will be removed from the queue, either when the lower layers will report // PDUs will be removed from the queue, either when the lower layers will report
// a succesfull transmission or when the discard timer expires. // a successfull transmission or when the discard timer expires.
// Status report will also use this queue, to know the First Missing SDU (FMS). // Status report will also use this queue, to know the First Missing SDU (FMS).
if (!rlc->rb_is_um(lcid) and is_drb()) { if (!rlc->rb_is_um(lcid) and is_drb()) {
if (not store_sdu(used_sn, sdu)) { if (not store_sdu(used_sn, sdu)) {

@ -178,7 +178,7 @@ int main(int argc, char** argv)
if (have_channel) { if (have_channel) {
// Add noise // Add noise
float std_dev = srsran_convert_dB_to_amplitude(-(snr_db + 3.0f)) * 0.1f; float std_dev = srsran_convert_dB_to_power(-(snr_db + 20.0f));
srsran_ch_awgn_c(est.pilot_recv_signal, est.pilot_recv_signal, std_dev, SRSRAN_REFSIGNAL_MAX_NUM_SF(1)); srsran_ch_awgn_c(est.pilot_recv_signal, est.pilot_recv_signal, std_dev, SRSRAN_REFSIGNAL_MAX_NUM_SF(1));
} }

@ -128,7 +128,6 @@ static inline void channel_awgn_run(srsran_channel_awgn_t* q, const float* in, f
#if SRSRAN_SIMD_F_SIZE #if SRSRAN_SIMD_F_SIZE
for (; i < (int)size - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) { for (; i < (int)size - SRSRAN_SIMD_F_SIZE + 1; i += SRSRAN_SIMD_F_SIZE) {
if (i % AWGN_TABLE_READ_BURST == 0) { if (i % AWGN_TABLE_READ_BURST == 0) {
idx1 = channel_awgn_rand(q); idx1 = channel_awgn_rand(q);
idx2 = channel_awgn_rand(q); idx2 = channel_awgn_rand(q);
@ -154,7 +153,6 @@ static inline void channel_awgn_run(srsran_channel_awgn_t* q, const float* in, f
#endif /* SRSRAN_SIMD_F_SIZE */ #endif /* SRSRAN_SIMD_F_SIZE */
for (; i < size; i++) { for (; i < size; i++) {
if (i % AWGN_TABLE_READ_BURST == 0) { if (i % AWGN_TABLE_READ_BURST == 0) {
idx1 = channel_awgn_rand(q); idx1 = channel_awgn_rand(q);
idx2 = channel_awgn_rand(q); idx2 = channel_awgn_rand(q);
@ -206,19 +204,21 @@ void srsran_ch_awgn_c(const cf_t* x, cf_t* y, float variance, uint32_t len)
{ {
cf_t tmp; cf_t tmp;
uint32_t i; uint32_t i;
float stddev = sqrtf(variance);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
__real__ tmp = rand_gauss(); __real__ tmp = rand_gauss();
__imag__ tmp = rand_gauss(); __imag__ tmp = rand_gauss();
tmp *= variance; tmp *= stddev * (float)M_SQRT1_2;
y[i] = tmp + x[i]; y[i] = tmp + x[i];
} }
} }
void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len) void srsran_ch_awgn_f(const float* x, float* y, float variance, uint32_t len)
{ {
uint32_t i; uint32_t i;
float stddev = sqrtf(variance);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
y[i] = x[i] + variance * rand_gauss(); y[i] = x[i] + stddev * rand_gauss();
} }
} }

@ -214,7 +214,7 @@ static int get_pucch(srsran_enb_ul_t* q, srsran_ul_sf_cfg_t* ul_sf, srsran_pucch
// Compares correlation value, it stores the PUCCH result with the greatest correlation // Compares correlation value, it stores the PUCCH result with the greatest correlation
if (i == 0 || pucch_res.correlation > res->correlation) { if (i == 0 || pucch_res.correlation > res->correlation) {
// Copy measurements only if PUCCH was decoded succesfully // Copy measurements only if PUCCH was decoded successfully
if (cfg->meas_ta_en) { if (cfg->meas_ta_en) {
pucch_res.ta_valid = !(isnan(q->chest_res.ta_us) || isinf(q->chest_res.ta_us)); pucch_res.ta_valid = !(isnan(q->chest_res.ta_us) || isinf(q->chest_res.ta_us));
pucch_res.ta_us = q->chest_res.ta_us; pucch_res.ta_us = q->chest_res.ta_us;

@ -193,13 +193,13 @@ int main(int argc, char** argv)
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc; ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[i] = srsran_convert_dB_to_amplitude(esno_db); var[i] = srsran_convert_dB_to_power(-esno_db);
varunc[i] = srsran_convert_dB_to_amplitude(ebno_db); varunc[i] = srsran_convert_dB_to_power(-ebno_db);
} }
} else { } else {
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[0] = srsran_convert_dB_to_amplitude(esno_db); var[0] = srsran_convert_dB_to_power(-esno_db);
varunc[0] = srsran_convert_dB_to_amplitude(ebno_db); varunc[0] = srsran_convert_dB_to_power(-ebno_db);
snr_points = 1; snr_points = 1;
} }

@ -323,6 +323,7 @@ int main(int argc, char** argv)
int n_error_words_avx512_flood = 0; int n_error_words_avx512_flood = 0;
#endif // lV_HAVE_AVX512 #endif // lV_HAVE_AVX512
float noise_var = srsran_convert_dB_to_power(-snr);
float noise_std_dev = srsran_convert_dB_to_amplitude(-snr); float noise_std_dev = srsran_convert_dB_to_amplitude(-snr);
int16_t inf15 = (1U << 14U) - 1; int16_t inf15 = (1U << 14U) - 1;
@ -380,12 +381,12 @@ int main(int argc, char** argv)
} }
// Apply AWGN // Apply AWGN
srsran_ch_awgn_f(symbols_rm, symbols_rm, noise_std_dev, batch_size * (rm_length + F)); srsran_ch_awgn_f(symbols_rm, symbols_rm, noise_var, batch_size * (rm_length + F));
// Convert symbols into LLRs // Convert symbols into LLRs
for (i = 0; i < batch_size; i++) { for (i = 0; i < batch_size; i++) {
for (j = 0; j < rm_length + F; j++) { //+F because we have already considered fillerbits when modulating. for (j = 0; j < rm_length + F; j++) { //+F because we have already considered fillerbits when modulating.
symbols[i * finalN + j] = symbols_rm[i * (rm_length + F) + j] * 2 / (noise_std_dev * noise_std_dev); symbols[i * finalN + j] = symbols_rm[i * (rm_length + F) + j] * 2 / noise_var;
} }
// the rest of symbols are undetermined, set LLR to 0 // the rest of symbols are undetermined, set LLR to 0
for (; j < finalN; j++) { for (; j < finalN; j++) {

@ -418,6 +418,7 @@ int main(int argc, char** argv)
int n_error_words_avx512_flood = 0; int n_error_words_avx512_flood = 0;
#endif // LV_HAVE_AVX512 #endif // LV_HAVE_AVX512
float noise_var = srsran_convert_dB_to_power(-snr);
float noise_std_dev = srsran_convert_dB_to_amplitude(-snr); float noise_std_dev = srsran_convert_dB_to_amplitude(-snr);
int16_t inf15 = (1U << 14U) - 1; int16_t inf15 = (1U << 14U) - 1;
@ -487,12 +488,12 @@ int main(int argc, char** argv)
} }
// Apply AWGN // Apply AWGN
srsran_ch_awgn_f(rm_symbols, rm_symbols, noise_std_dev, batch_size * rm_length); srsran_ch_awgn_f(rm_symbols, rm_symbols, noise_var, batch_size * rm_length);
// Convert symbols into LLRs // Convert symbols into LLRs
for (i = 0; i < batch_size; i++) { for (i = 0; i < batch_size; i++) {
for (j = 0; j < rm_length; j++) { for (j = 0; j < rm_length; j++) {
rm_symbols[i * rm_length + j] = rm_symbols[i * rm_length + j] * 2 / (noise_std_dev * noise_std_dev); rm_symbols[i * rm_length + j] = rm_symbols[i * rm_length + j] * 2 / noise_var;
} }
} }

@ -193,9 +193,9 @@ int main(int argc, char** argv)
int j = 0; int j = 0;
int snr_points = 0; int snr_points = 0;
int errors_symb = 0; int errors_symb = 0;
int errors_symb_s = 0; int errors_symb_s = 0;
int errors_symb_c = 0; int errors_symb_c = 0;
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
int errors_symb_c_avx2 = 0; int errors_symb_c_avx2 = 0;
#endif #endif
@ -217,12 +217,12 @@ int main(int argc, char** argv)
double elapsed_time_enc_avx2[SNR_POINTS + 1]; double elapsed_time_enc_avx2[SNR_POINTS + 1];
// 16-bit quantizer // 16-bit quantizer
int16_t inf16 = (1U << 15U) - 1; int16_t inf16 = (1U << 15U) - 1;
int8_t inf8 = (1U << 7U) - 1; int8_t inf8 = (1U << 7U) - 1;
float gain_s = NAN; float gain_s = NAN;
float gain_c = NAN; float gain_c = NAN;
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
float gain_c_avx2 = NAN; float gain_c_avx2 = NAN;
#endif #endif
srsran_polar_code_t code; srsran_polar_code_t code;
@ -328,13 +328,13 @@ int main(int argc, char** argv)
for (int i = 0; i < snr_points; i++) { for (int i = 0; i < snr_points; i++) {
snr_db = SNR_MIN + i * snr_inc; snr_db = SNR_MIN + i * snr_inc;
snr_db_vec[i] = snr_db; snr_db_vec[i] = snr_db;
var[i] = srsran_convert_dB_to_amplitude(-snr_db); var[i] = srsran_convert_dB_to_power(-snr_db);
} }
snr_db_vec[snr_points] = 101; // include the no noise case snr_db_vec[snr_points] = 101; // include the no noise case
snr_points++; snr_points++;
} else { } else {
snr_db_vec[0] = snr_db; snr_db_vec[0] = snr_db;
var[0] = srsran_convert_dB_to_amplitude(-snr_db); var[0] = srsran_convert_dB_to_power(-snr_db);
snr_points = 1; snr_points = 1;
} }

@ -215,11 +215,11 @@ int main(int argc, char** argv)
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc; ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[i] = srsran_convert_dB_to_amplitude(-esno_db); var[i] = srsran_convert_dB_to_power(-esno_db);
} }
} else { } else {
esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f); esno_db = ebno_db + srsran_convert_power_to_dB(1.0f / 3.0f);
var[0] = srsran_convert_dB_to_amplitude(-esno_db); var[0] = srsran_convert_dB_to_power(-esno_db);
snr_points = 1; snr_points = 1;
} }
for (uint32_t i = 0; i < snr_points; i++) { for (uint32_t i = 0; i < snr_points; i++) {

@ -163,10 +163,10 @@ void populate_channel(srsran_tx_scheme_t type, cf_t* h[SRSRAN_MAX_PORTS][SRSRAN_
static void awgn(cf_t* y[SRSRAN_MAX_PORTS], uint32_t n, float snr) static void awgn(cf_t* y[SRSRAN_MAX_PORTS], uint32_t n, float snr)
{ {
int i; int i;
float std_dev = srsran_convert_dB_to_amplitude(-(snr + 3.0f)) * scaling; float var = srsran_convert_dB_to_power(-snr) * scaling * scaling;
for (i = 0; i < nof_rx_ports; i++) { for (i = 0; i < nof_rx_ports; i++) {
srsran_ch_awgn_c(y[i], y[i], std_dev, n); srsran_ch_awgn_c(y[i], y[i], var, n);
} }
} }

@ -2080,7 +2080,7 @@ uint32_t srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t
len = srsran_print_check(str, len = srsran_print_check(str,
str_len, str_len,
len, len,
"%s-rnti=%04x dci=%s ss=%s ", "%s-rnti=0x%04x dci=%s ss=%s ",
srsran_rnti_type_str_short(ctx->rnti_type), srsran_rnti_type_str_short(ctx->rnti_type),
ctx->rnti, ctx->rnti,
srsran_dci_format_nr_string(ctx->format), srsran_dci_format_nr_string(ctx->format),

@ -222,8 +222,8 @@ int main(int argc, char** argv)
// add some noise to the signal // add some noise to the signal
if (snr != -1.0) { if (snr != -1.0) {
float nstd = powf(10.0f, -snr / 20.0f); float var = srsran_convert_dB_to_power(-snr);
srsran_ch_awgn_c(buff_ptrs[0], buff_ptrs[0], nstd, nread); srsran_ch_awgn_c(buff_ptrs[0], buff_ptrs[0], var, nread);
} }
// try to decode // try to decode

@ -592,10 +592,6 @@ int rf_skiq_set_rx_gain_ch(void* h_, uint32_t ch, double rx_gain)
rx_gain = rf_skiq_card_set_rx_gain_db(&h->cards[card_idx], port_idx, rx_gain); rx_gain = rf_skiq_card_set_rx_gain_db(&h->cards[card_idx], port_idx, rx_gain);
if (ch == 0) {
h->cur_tx_gain = rx_gain;
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -620,12 +616,10 @@ srsran_rf_info_t* rf_skiq_get_info(void* h_)
if (h != NULL) { if (h != NULL) {
ret = &h->info; ret = &h->info;
rf_skiq_card_update_gain_table(&h->cards[0]);
ret->min_tx_gain = 0.25 * (double)h->cards[0].param.tx_param->atten_quarter_db_max; ret->min_tx_gain = 0.25 * (double)h->cards[0].param.tx_param->atten_quarter_db_max;
ret->max_tx_gain = 0.25 * (double)h->cards[0].param.tx_param->atten_quarter_db_min; ret->max_tx_gain = 0.25 * (double)h->cards[0].param.tx_param->atten_quarter_db_min;
ret->min_rx_gain = h->cards[0].rx_gain_table_db[h->cards[0].param.rx_param[0].gain_index_min]; ret->min_rx_gain = h->cards[0].param.rx_param[0].gain_index_min;
ret->max_rx_gain = h->cards[0].rx_gain_table_db[h->cards[0].param.rx_param[0].gain_index_max]; ret->max_rx_gain = h->cards[0].param.rx_param[0].gain_index_max;
} }
return ret; return ret;

@ -49,21 +49,6 @@ static void* reader_thread(void* arg)
switch (rx_status) { switch (rx_status) {
case skiq_rx_status_success: case skiq_rx_status_success:
// Check Rx index boundary
if (p_rx_block->rfic_control >= q->param.rx_param->gain_index_min &&
p_rx_block->rfic_control <= q->param.rx_param->gain_index_max) {
double new_rx_gain = q->rx_gain_table_db[p_rx_block->rfic_control];
// If the Rx index has changed, update gain
if (new_rx_gain != q->cur_rx_gain_db) {
SKIQ_RF_DEBUG("card %d index=%d; gain=%.2f/%.2f dB;\n",
q->card,
p_rx_block->rfic_control,
q->rx_gain_table_db[p_rx_block->rfic_control],
q->cur_rx_gain_db);
q->cur_rx_gain_db = new_rx_gain;
}
}
if (curr_rx_hdl < q->nof_ports && p_rx_block != NULL && len > SKIQ_RX_HEADER_SIZE_IN_BYTES) { if (curr_rx_hdl < q->nof_ports && p_rx_block != NULL && len > SKIQ_RX_HEADER_SIZE_IN_BYTES) {
// Convert number of bytes into samples // Convert number of bytes into samples
uint32_t nsamples = len / 4 - SKIQ_RX_HEADER_SIZE_IN_WORDS; uint32_t nsamples = len / 4 - SKIQ_RX_HEADER_SIZE_IN_WORDS;
@ -103,17 +88,6 @@ static void* reader_thread(void* arg)
return NULL; return NULL;
} }
int rf_skiq_card_update_gain_table(rf_skiq_card_t* q)
{
for (uint8_t i = q->param.rx_param->gain_index_min; i <= q->param.rx_param->gain_index_max; i++) {
if (skiq_read_rx_cal_offset_by_gain_index(q->card, skiq_rx_hdl_A1, i, &q->rx_gain_table_db[i])) {
ERROR("Reading calibrated Rx gain index %d", i);
return SRSRAN_ERROR;
}
}
return SRSRAN_SUCCESS;
}
int rf_skiq_card_init(rf_skiq_card_t* q, uint8_t card, uint8_t nof_ports, const rf_skiq_port_opts_t* opts) int rf_skiq_card_init(rf_skiq_card_t* q, uint8_t card, uint8_t nof_ports, const rf_skiq_port_opts_t* opts)
{ {
q->card = card; q->card = card;
@ -292,32 +266,39 @@ double rf_skiq_card_set_tx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double
double rf_skiq_card_set_rx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db) double rf_skiq_card_set_rx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db)
{ {
// Find the nearest gain index in the table // From Sidekiq API doc:
int gain_idx = -1; //
double gain_min_diff = INFINITY; // For Sidekiq mPCIe (skiq_mpcie), Sidekiq M.2 (skiq_m2), Sidekiq Stretch (skiq_m2_2280), Sidekiq Z2
for (int i = q->param.rx_param->gain_index_min; i <= q->param.rx_param->gain_index_max; i++) { //(skiq_z2), and Matchstiq Z3u (skiq_z3u) each increment of the gain index value results in approxi-
double gain_diff = fabs(q->rx_gain_table_db[i] - gain_db); // mately 1 dB of gain, with approximately 76 dB of total gain available. For details on the gain table,
if (gain_diff < gain_min_diff) { // refer to p. 37 of AD9361 Reference Manual UG-570
gain_min_diff = gain_diff;
gain_idx = i; // Check gain range
} if (gain_db < q->param.rx_param->gain_index_min || gain_db > q->param.rx_param->gain_index_max) {
ERROR("Error port %d:%d the selected gain (%.2f dB) is out of range (%d to %d dB).\n",
q->card,
port_idx,
gain_db,
q->param.rx_param->gain_index_min,
q->param.rx_param->gain_index_max);
} }
if (gain_idx >= 0) { // Calculate attenuation index
gain_db = q->rx_gain_table_db[gain_idx]; uint16_t gain_idx = (uint16_t)floor(gain_db);
if (port_idx < q->nof_ports) {
// Set single port gain if (port_idx < q->nof_ports) {
q->issued_rx_gain_db[port_idx] = gain_db; // Set single port gain
skiq_write_rx_gain(q->card, (skiq_rx_hdl_t)port_idx, gain_idx); skiq_write_rx_gain(q->card, (skiq_rx_hdl_t)port_idx, gain_idx);
} else { } else {
// Set all gains // Set all gains
for (int i = 0; i < q->nof_ports; i++) { for (int i = 0; i < q->nof_ports; i++) {
q->issued_rx_gain_db[i] = gain_db; skiq_write_rx_gain(q->card, (skiq_rx_hdl_t)i, gain_idx);
skiq_write_rx_gain(q->card, (skiq_rx_hdl_t)i, gain_idx);
}
} }
} }
// Update current rx_gain
q->cur_rx_gain_db = gain_db;
return gain_db; return gain_db;
} }
@ -520,16 +501,6 @@ double rf_skiq_card_set_rx_freq_hz(rf_skiq_card_t* q, uint32_t port_idx, double
q->suspend = true; q->suspend = true;
rf_skiq_rx_port_set_lo(&q->rx_ports[port_idx], (uint64_t)freq_hz); rf_skiq_rx_port_set_lo(&q->rx_ports[port_idx], (uint64_t)freq_hz);
q->suspend = false; q->suspend = false;
// Update gains for only port 0
if (port_idx == 0) {
// Update gain table
rf_skiq_card_update_gain_table(q);
// Set previous issued gain in dB for the new tables
rf_skiq_card_set_rx_gain_db(q, q->nof_ports, q->issued_rx_gain_db[port_idx]);
}
return freq_hz; return freq_hz;
} }

@ -32,9 +32,7 @@ typedef struct {
rf_skiq_tx_port_t tx_ports[RF_SKIQ_MAX_PORTS_CARD]; rf_skiq_tx_port_t tx_ports[RF_SKIQ_MAX_PORTS_CARD];
rf_skiq_rx_port_t rx_ports[RF_SKIQ_MAX_PORTS_CARD]; rf_skiq_rx_port_t rx_ports[RF_SKIQ_MAX_PORTS_CARD];
double rx_gain_table_db[UINT8_MAX + 1];
double cur_rx_gain_db; double cur_rx_gain_db;
double issued_rx_gain_db[SRSRAN_MAX_PORTS];
bool suspend; bool suspend;
uint64_t start_rx_stream_ts; uint64_t start_rx_stream_ts;
@ -49,8 +47,6 @@ int rf_skiq_card_init(rf_skiq_card_t* q, uint8_t card, uint8_t nof_ports, const
void rf_skiq_card_set_error_handler(rf_skiq_card_t* q, srsran_rf_error_handler_t error_handler, void* arg); void rf_skiq_card_set_error_handler(rf_skiq_card_t* q, srsran_rf_error_handler_t error_handler, void* arg);
int rf_skiq_card_update_gain_table(rf_skiq_card_t* q);
double rf_skiq_card_set_tx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db); double rf_skiq_card_set_tx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db);
double rf_skiq_card_set_rx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db); double rf_skiq_card_set_rx_gain_db(rf_skiq_card_t* q, uint32_t port_idx, double gain_db);

@ -827,7 +827,7 @@ static int uhd_init(rf_uhd_handler_t* handler, char* args, uint32_t nof_channels
if (clock_src != "internal") { if (clock_src != "internal") {
// blocks until clock source is locked // blocks until clock source is locked
int error = wait_sensor_locked(handler, sensor_name, true, 300, is_locked); int error = wait_sensor_locked(handler, sensor_name, true, 300, is_locked);
// Print Not lock error if the return was succesful, wait_sensor_locked prints the error before returning // Print Not lock error if the return was successful, wait_sensor_locked prints the error before returning
if (not is_locked and error == SRSRAN_SUCCESS) { if (not is_locked and error == SRSRAN_SUCCESS) {
ERROR( ERROR(
"Could not lock reference clock source. Sensor: %s=%s\n", sensor_name.c_str(), is_locked ? "true" : "false"); "Could not lock reference clock source. Sensor: %s=%s\n", sensor_name.c_str(), is_locked ? "true" : "false");

@ -624,7 +624,11 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, uint32_t t_offset, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) static int ssb_demodulate(srsran_ssb_t* q,
const cf_t* in,
uint32_t t_offset,
float coarse_cfo_hz,
cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
{ {
const cf_t* in_ptr = &in[t_offset]; const cf_t* in_ptr = &in[t_offset];
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
@ -632,11 +636,16 @@ static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, uint32_t t_offset, cf
in_ptr += SRSRAN_FLOOR(q->cp_sz, 2); in_ptr += SRSRAN_FLOOR(q->cp_sz, 2);
// Copy FFT window in temporal time domain buffer // Copy FFT window in temporal time domain buffer
srsran_vec_cf_copy(q->tmp_time, in_ptr, q->symbol_sz); if (isnormal(coarse_cfo_hz)) {
srsran_vec_apply_cfo(in_ptr, (float)(-coarse_cfo_hz / q->cfg.srate_hz), q->tmp_time, q->symbol_sz);
} else {
srsran_vec_cf_copy(q->tmp_time, in_ptr, q->symbol_sz);
}
in_ptr += q->symbol_sz + SRSRAN_CEIL(q->cp_sz, 2); in_ptr += q->symbol_sz + SRSRAN_CEIL(q->cp_sz, 2);
// Phase compensation // Phase compensation
cf_t phase_compensation = (cf_t)cexp(-I * 2.0 * M_PI * q->cfg.center_freq_hz * (double)t_offset / q->cfg.srate_hz); cf_t phase_compensation =
(cf_t)cexp(-I * 2.0 * M_PI * (q->cfg.center_freq_hz - coarse_cfo_hz) * (double)t_offset / q->cfg.srate_hz);
t_offset += q->symbol_sz + q->cp_sz; t_offset += q->symbol_sz + q->cp_sz;
// Convert to frequency domain // Convert to frequency domain
@ -727,18 +736,25 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_
float rsrp_sss = SRSRAN_CSQABS(corr_sss); float rsrp_sss = SRSRAN_CSQABS(corr_sss);
float rsrp = (rsrp_pss + rsrp_sss) / 2.0f; float rsrp = (rsrp_pss + rsrp_sss) / 2.0f;
// avoid taking log of 0 (NaN) // Avoid taking log of 0 or another abnormal value
if (rsrp == 0.0) { if (!isnormal(rsrp)) {
rsrp = 1.0; rsrp = 1e-9f;
} }
// Compute Noise // Estimate Noise:
float n0_pss = 1e-9; // Almost 0 // - Infinite (1e9), if the EPRE or RSRP is zero
float n0_sss = 1e-9; // Almost 0 // - EPRE-RSRP if EPRE > RSRP
if (epre_pss > rsrp_pss) { // - zero (1e-9), otherwise
float n0_pss = 1e-9f;
if (!isnormal(epre_pss) || !isnormal(rsrp_pss)) {
n0_pss = 1e9f;
} else if (epre_pss > rsrp_pss) {
n0_pss = epre - rsrp_pss; n0_pss = epre - rsrp_pss;
} }
if (epre_sss > rsrp_sss) { float n0_sss = 1e-9f;
if (!isnormal(epre_sss) || !isnormal(rsrp_sss)) {
n0_sss = 1e9f;
} else if (epre_sss > rsrp_sss) {
n0_sss = epre - rsrp_sss; n0_sss = epre - rsrp_sss;
} }
float n0 = (n0_pss + n0_sss) / 2.0f; float n0 = (n0_pss + n0_sss) / 2.0f;
@ -759,18 +775,60 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static int static void ssb_vec_prod_conj_circ_shift(const cf_t* a, const cf_t* b, cf_t* c, uint32_t n, int shift)
ssb_pss_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t* found_N_id_2, uint32_t* found_delay) {
uint32_t offset = (uint32_t)abs(shift);
// Avoid negative number of samples
if (offset > n) {
srsran_vec_cf_zero(c, n);
return;
}
// Shift is negative
if (shift < 0) {
srsran_vec_prod_conj_ccc(&a[offset], &b[0], &c[0], n - offset);
srsran_vec_prod_conj_ccc(&a[0], &b[n - offset], &c[n - offset], offset);
return;
}
// Shift is positive
if (shift > 0) {
srsran_vec_prod_conj_ccc(&a[0], &b[offset], &c[0], n - offset);
srsran_vec_prod_conj_ccc(&a[n - offset], &b[0], &c[n - offset], offset);
return;
}
// Shift is zero
srsran_vec_prod_conj_ccc(a, b, c, n);
}
static int ssb_pss_search(srsran_ssb_t* q,
const cf_t* in,
uint32_t nof_samples,
uint32_t* found_N_id_2,
uint32_t* found_delay,
float* coarse_cfo_hz)
{ {
// verify it is initialised // verify it is initialised
if (q->corr_sz == 0) { if (q->corr_sz == 0) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Calculate correlation CFO coarse precision
double coarse_cfo_ref_hz = (q->cfg.srate_hz / q->corr_sz);
// Calculate shift integer range to detect the signal with a maximum CFO equal to the SSB subcarrier spacing
int shift_range = (int)ceil(SRSRAN_SUBC_SPACING_NR(q->cfg.scs) / coarse_cfo_ref_hz);
// Calculate the coarse shift increment for half of the subcarrier spacing
int shift_coarse_inc = shift_range / 2;
// Correlation best sequence // Correlation best sequence
float best_corr = 0; float best_corr = 0;
uint32_t best_delay = 0; uint32_t best_delay = 0;
uint32_t best_N_id_2 = 0; uint32_t best_N_id_2 = 0;
int best_shift = 0;
// Delay in correlation window // Delay in correlation window
uint32_t t_offset = 0; uint32_t t_offset = 0;
@ -796,39 +854,83 @@ ssb_pss_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t*
// Try each N_id_2 sequence // Try each N_id_2 sequence
for (uint32_t N_id_2 = 0; N_id_2 < SRSRAN_NOF_NID_2_NR; N_id_2++) { for (uint32_t N_id_2 = 0; N_id_2 < SRSRAN_NOF_NID_2_NR; N_id_2++) {
// Actual correlation in frequency domain // Steer coarse frequency offset
srsran_vec_prod_conj_ccc(q->tmp_freq, q->pss_seq[N_id_2], q->tmp_corr, q->corr_sz); for (int shift = -shift_range; shift <= shift_range; shift += shift_coarse_inc) {
// Actual correlation in frequency domain
ssb_vec_prod_conj_circ_shift(q->tmp_freq, q->pss_seq[N_id_2], q->tmp_corr, q->corr_sz, shift);
// Convert to time domain
srsran_dft_run_guru_c(&q->ifft_corr);
// 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);
if (!isnormal(avg_pwr_corr)) {
continue;
}
// Normalise correlation
float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr / sqrtf(SRSRAN_PSS_NR_LEN);
// Update if the correlation is better than the current best
if (best_corr < corr) {
best_corr = corr;
best_delay = peak_idx + t_offset;
best_N_id_2 = N_id_2;
best_shift = shift;
}
}
}
// Convert to time domain // Advance time
srsran_dft_run_guru_c(&q->ifft_corr); t_offset += q->corr_window;
}
// Find maximum // From the best sequence correlate in frequency domain
uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window); {
// Reset best correlation
best_corr = 0.0f;
// Average power, skip window if value is invalid (0.0, nan or inf) // Number of samples taken in this iteration
float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz); uint32_t n = q->corr_sz;
if (!isnormal(avg_pwr_corr)) {
continue; // Detect if the correlation input exceeds the input length, take the maximum amount of samples
} if (best_delay + q->corr_sz > nof_samples) {
n = nof_samples - best_delay;
}
// Copy the amount of samples
srsran_vec_cf_copy(q->tmp_time, &in[best_delay], n);
// Append zeros if there is space left
if (n < q->corr_sz) {
srsran_vec_cf_zero(&q->tmp_time[n], q->corr_sz - n);
}
// Convert to frequency domain
srsran_dft_run_guru_c(&q->fft_corr);
// Normalise correlation for (int shift = -shift_range; shift <= shift_range; shift++) {
float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr / sqrtf(SRSRAN_PSS_NR_LEN); // Actual correlation in frequency domain
ssb_vec_prod_conj_circ_shift(q->tmp_freq, q->pss_seq[best_N_id_2], q->tmp_corr, q->corr_sz, shift);
// Calculate correlation assuming the peak is in the first sample
float corr = SRSRAN_CSQABS(srsran_vec_acc_cc(q->tmp_corr, q->corr_sz));
// Update if the correlation is better than the current best // Update if the correlation is better than the current best
if (best_corr < corr) { if (best_corr < corr) {
best_corr = corr; best_corr = corr;
best_delay = peak_idx + t_offset; best_shift = shift;
best_N_id_2 = N_id_2;
} }
} }
// Advance time
t_offset += q->corr_window;
} }
// Save findings // Save findings
*found_delay = best_delay; *found_delay = best_delay;
*found_N_id_2 = best_N_id_2; *found_N_id_2 = best_N_id_2;
*coarse_cfo_hz = -(float)best_shift * coarse_cfo_ref_hz;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -857,9 +959,10 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
nof_samples -= (q->symbol_sz + q->cp_sz) * SRSRAN_SSB_DURATION_NSYMB; nof_samples -= (q->symbol_sz + q->cp_sz) * SRSRAN_SSB_DURATION_NSYMB;
// Search for PSS in time domain // Search for PSS in time domain
uint32_t N_id_2 = 0; uint32_t N_id_2 = 0;
uint32_t t_offset = 0; uint32_t t_offset = 0;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset) < SRSRAN_SUCCESS) { float coarse_cfo_hz = 0.0f;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset, &coarse_cfo_hz) < SRSRAN_SUCCESS) {
ERROR("Error searching for N_id_2"); ERROR("Error searching for N_id_2");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -873,7 +976,7 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -897,6 +1000,7 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
// Add delay to measure // Add delay to measure
meas->delay_us += (float)(1e6 * t_offset / q->cfg.srate_hz); meas->delay_us += (float)(1e6 * t_offset / q->cfg.srate_hz);
meas->cfo_hz -= coarse_cfo_hz;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -925,7 +1029,7 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q,
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, in, (uint32_t)t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1054,7 +1158,7 @@ int srsran_ssb_decode_pbch(srsran_ssb_t* q,
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, in, (uint32_t)t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1083,9 +1187,10 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
} }
// Search for PSS in time domain // Search for PSS in time domain
uint32_t N_id_2 = 0; uint32_t N_id_2 = 0;
uint32_t t_offset = 0; uint32_t t_offset = 0;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset) < SRSRAN_SUCCESS) { float coarse_cfo_hz = 0.0f;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset, &coarse_cfo_hz) < SRSRAN_SUCCESS) {
ERROR("Error searching for N_id_2"); ERROR("Error searching for N_id_2");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1099,7 +1204,7 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1141,6 +1246,7 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
res->t_offset = t_offset; res->t_offset = t_offset;
res->pbch_msg = pbch_msg; res->pbch_msg = pbch_msg;
res->measurements = measurements; res->measurements = measurements;
res->measurements.cfo_hz += coarse_cfo_hz;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -1190,6 +1296,8 @@ static int ssb_pss_find(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, u
// Average power, skip window if value is invalid (0.0, nan or inf) // 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); float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz);
if (!isnormal(avg_pwr_corr)) { if (!isnormal(avg_pwr_corr)) {
// Advance time
t_offset += q->corr_window;
continue; continue;
} }
@ -1250,7 +1358,7 @@ int srsran_ssb_find(srsran_ssb_t* q,
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, q->sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, q->sf_buffer, t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1310,7 +1418,7 @@ int srsran_ssb_track(srsran_ssb_t* q,
// Demodulate // Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) { if (ssb_demodulate(q, sf_buffer, t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating"); ERROR("Error demodulating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1354,3 +1462,25 @@ uint32_t srsran_ssb_candidate_sf_offset(const srsran_ssb_t* q, uint32_t ssb_idx)
return cp_sz_0 + l * (q->symbol_sz + q->cp_sz); return cp_sz_0 + l * (q->symbol_sz + q->cp_sz);
} }
uint32_t srsran_ssb_cfg_to_str(const srsran_ssb_cfg_t* cfg, char* str, uint32_t str_len)
{
uint32_t n = 0;
n = srsran_print_check(str,
str_len,
n,
"srate=%.2f MHz; c-freq=%.3f MHz; ss-freq=%.3f MHz; scs=%s; pattern=%s; duplex=%s;",
cfg->srate_hz / 1e6,
cfg->center_freq_hz / 1e6,
cfg->ssb_freq_hz / 1e6,
srsran_subcarrier_spacing_to_str(cfg->scs),
srsran_ssb_pattern_to_str(cfg->pattern),
cfg->duplex_mode == SRSRAN_DUPLEX_MODE_FDD ? "fdd" : "tdd");
if (cfg->periodicity_ms > 0) {
n = srsran_print_check(str, str_len, n, " period=%d ms;", cfg->periodicity_ms);
}
return n;
}

@ -184,8 +184,8 @@ int main(int argc, char** argv)
if (snr != -1.0) { if (snr != -1.0) {
snr -= 10.0; snr -= 10.0;
printf("Adding AWGN with target SNR: %.2fdB\n", snr); printf("Adding AWGN with target SNR: %.2fdB\n", snr);
float nstd = srsran_convert_dB_to_amplitude(-snr); float var = srsran_convert_dB_to_power(-snr);
srsran_ch_awgn_c(fft_buffer, fft_buffer, nstd, SFLEN); srsran_ch_awgn_c(fft_buffer, fft_buffer, var, SFLEN);
} }
// look for NPSS signal // look for NPSS signal

@ -175,8 +175,8 @@ int main(int argc, char** argv)
// ADD CHANNEL NOISE // ADD CHANNEL NOISE
if (snr < 50) { if (snr < 50) {
float std_dev = powf(10.0f, -(snr + 3.0f) / 20.0f); float var = srsran_convert_dB_to_power(-snr);
srsran_ch_awgn_c(output_buffer, output_buffer, std_dev, output_buffer_len); srsran_ch_awgn_c(output_buffer, output_buffer, var, output_buffer_len);
} }
// ADD FREQUENCY OFFSET // ADD FREQUENCY OFFSET

@ -69,5 +69,5 @@ endforeach ()
#add_test(ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0.dat -i 1 -P 52 -n 4 -R 7f) #add_test(ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0.dat -i 1 -P 52 -n 4 -R 7f)
add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx6 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 6 -s common0 -A 368500 -a 368410) add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx6 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 6 -s common0 -A 368500 -a 368410)
#add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx7 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 7 -s common0 -A 161200 -a 161290) #add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx7 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 7 -s common0 -A 161200 -a 161290)
#add_test(ue_dl_nr_pci500_rb52_pdsch ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -o 2 -s common3) add_test(ue_dl_nr_pci500_rb52_pdsch ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat -S -i 500 -P 52 -N 48 -n 1 -R 0x100 -T c -s common3 -o 1 -A 368500 -a 368410 -I -t 1 13)
add_test(ue_dl_nr_pci500_rb52_rar ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat -i 500 -P 52 -n 5 -R f -T ra -c 6 -S -s common1 -A 368500 -a 368410) add_test(ue_dl_nr_pci500_rb52_rar ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat -i 500 -P 52 -n 5 -R f -T ra -c 6 -S -s common1 -A 368500 -a 368410)

@ -26,6 +26,7 @@ extern "C" {
#include "srsran/phy/phch/ra_nr.h" #include "srsran/phy/phch/ra_nr.h"
#include "srsran/phy/ue/ue_dl_nr.h" #include "srsran/phy/ue/ue_dl_nr.h"
#include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/debug.h"
#include <srsran/phy/common/sliv.h>
} }
#endif // __cplusplus #endif // __cplusplus
@ -46,12 +47,14 @@ static srsran_ue_dl_nr_t ue_dl = {};
static cf_t* buffer[SRSRAN_MAX_PORTS] = {}; static cf_t* buffer[SRSRAN_MAX_PORTS] = {};
static srsran_softbuffer_rx_t softbuffer = {}; static srsran_softbuffer_rx_t softbuffer = {};
static uint8_t* data = NULL; static uint8_t* data = NULL;
static int pdsch_time_ra_start = -1;
static int pdsch_time_ra_length = -1;
static uint32_t coreset0_idx = 0; // if ss_type=si coreset0 is used and this is the index static uint32_t coreset0_idx = 0; // if ss_type=si coreset0 is used and this is the index
static uint32_t coreset_offset_rb = 0; static uint32_t coreset_offset_rb = 0;
static bool interleaved_pdcch = false;
static uint32_t dl_arfcn = 161200; // center of the NR carrier (default at 806e6 Hz) static uint32_t dl_arfcn = 161200; // center of the NR carrier (default at 806e6 Hz)
static uint32_t ssb_arfcn = 161290; // center of the SSB within the carrier (default at 806.45e6) static uint32_t ssb_arfcn = 161290; // center of the SSB within the carrier (default at 806.45e6)
static uint32_t coreset_n_rb = 48; static uint32_t coreset_n_rb = 48;
static uint32_t coreset_len = 1; static uint32_t coreset_len = 1;
@ -59,19 +62,20 @@ static srsran_search_space_type_t ss_type = srsran_search_space_type_common
static void usage(char* prog) static void usage(char* prog)
{ {
printf("Usage: %s [pTLR] \n", prog); printf("Usage: %s [fPivnSRTscoNlAaIt] \n", prog);
printf("\t-f File name [Default none]\n"); printf("\t-f File name [Default none]\n");
printf("\t-P Number of BWP (Carrier) PRB [Default %d]\n", carrier.nof_prb); printf("\t-P Number of BWP (Carrier) PRB [Default %d]\n", carrier.nof_prb);
printf("\t-i Physical cell identifier [Default %d]\n", carrier.pci); printf("\t-i Physical cell identifier [Default %d]\n", carrier.pci);
printf("\t-n Slot index [Default %d]\n", slot_cfg.idx); printf("\t-n Slot index [Default %d]\n", slot_cfg.idx);
printf("\t-R RNTI in hexadecimal [Default 0x%x]\n", rnti); printf("\t-R RNTI in hexadecimal [Default 0x%x]\n", rnti);
printf("\t-T RNTI type (c, ra, si) [Default %s]\n", srsran_rnti_type_str(rnti_type)); printf("\t-T RNTI type (c, ra, si) [Default %s]\n", srsran_rnti_type_str(rnti_type));
printf("\t-s Search space type (common0, common3) [Default %s]\n", srsran_ss_type_str(ss_type)); printf("\t-s Search space type (common0, common3, ue) [Default %s]\n", srsran_ss_type_str(ss_type));
printf("\t-c Coreset0 index (only used if SS type is common0 for SIB) [Default %d]\n", coreset0_idx); printf("\t-c Coreset0 index (only used if SS type is common0 for SIB) [Default %d]\n", coreset0_idx);
printf("\t-o Coreset RB offset [Default %d]\n", coreset_offset_rb); printf("\t-o Coreset RB offset [Default %d]\n", coreset_offset_rb);
printf("\t-N Coreset N_RB [Default %d]\n", coreset_n_rb); printf("\t-N Coreset N_RB [Default %d]\n", coreset_n_rb);
printf("\t-l Coreset duration in symbols [Default %d]\n", coreset_len); printf("\t-l Coreset duration in symbols [Default %d]\n", coreset_len);
printf("\t-I Enable interleaved CCE-to-REG [Default %s]\n", interleaved_pdcch ? "Enabled" : "Disabled");
printf("\t-t PDSCH time resource allocation [start symbol] [length]\n");
printf("\t-A ARFCN of the NR carrier (center) [Default %d]\n", dl_arfcn); printf("\t-A ARFCN of the NR carrier (center) [Default %d]\n", dl_arfcn);
printf("\t-a center of the SSB within the carrier [Default %d]\n", ssb_arfcn); printf("\t-a center of the SSB within the carrier [Default %d]\n", ssb_arfcn);
@ -83,7 +87,7 @@ static void usage(char* prog)
static int parse_args(int argc, char** argv) static int parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "fPivnSRTscoNlAa")) != -1) { while ((opt = getopt(argc, argv, "fPivnSRTscoNlAaIt")) != -1) {
switch (opt) { switch (opt) {
case 'f': case 'f':
filename = argv[optind]; filename = argv[optind];
@ -103,6 +107,10 @@ static int parse_args(int argc, char** argv)
case 'R': case 'R':
rnti = (uint16_t)strtol(argv[optind], NULL, 16); rnti = (uint16_t)strtol(argv[optind], NULL, 16);
break; break;
case 't':
pdsch_time_ra_start = (int)strtol(argv[optind++], NULL, 10);
pdsch_time_ra_length = (int)strtol(argv[optind], NULL, 10);
break;
case 'T': case 'T':
if (strcmp(argv[optind], "c") == 0) { if (strcmp(argv[optind], "c") == 0) {
rnti_type = srsran_rnti_type_c; rnti_type = srsran_rnti_type_c;
@ -131,6 +139,9 @@ static int parse_args(int argc, char** argv)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
break; break;
case 'I':
interleaved_pdcch ^= true;
break;
case 'c': case 'c':
coreset0_idx = (uint16_t)strtol(argv[optind], NULL, 10); coreset0_idx = (uint16_t)strtol(argv[optind], NULL, 10);
break; break;
@ -325,7 +336,16 @@ int main(int argc, char** argv)
srsran_dci_cfg_nr_t dci_cfg = {}; srsran_dci_cfg_nr_t dci_cfg = {};
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb; dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb; dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.bwp_dl_active_bw = carrier.nof_prb;
dci_cfg.bwp_ul_active_bw = carrier.nof_prb;
dci_cfg.monitor_common_0_0 = true; dci_cfg.monitor_common_0_0 = true;
dci_cfg.monitor_0_0_and_1_0 = true;
// derive absolute frequencies from ARFCNs
srsran::srsran_band_helper band_helper;
carrier.ssb_center_freq_hz = band_helper.nr_arfcn_to_freq(ssb_arfcn);
carrier.dl_center_frequency_hz = band_helper.nr_arfcn_to_freq(dl_arfcn);
srsran_coreset_t* coreset = NULL; srsran_coreset_t* coreset = NULL;
@ -335,18 +355,13 @@ int main(int argc, char** argv)
coreset = &pdcch_cfg.coreset[0]; coreset = &pdcch_cfg.coreset[0];
pdcch_cfg.coreset_present[0] = true; pdcch_cfg.coreset_present[0] = true;
// derive absolute frequencies from ARFCNs
srsran::srsran_band_helper band_helper;
carrier.ssb_center_freq_hz = band_helper.nr_arfcn_to_freq(ssb_arfcn);
carrier.dl_center_frequency_hz = band_helper.nr_arfcn_to_freq(dl_arfcn);
// Get pointA and SSB absolute frequencies // Get pointA and SSB absolute frequencies
double pointA_abs_freq_Hz = double pointA_abs_freq_Hz =
carrier.dl_center_frequency_hz - carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(carrier.scs) / 2; carrier.dl_center_frequency_hz - carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(carrier.scs) / 2;
double ssb_abs_freq_Hz = carrier.ssb_center_freq_hz; double ssb_abs_freq_Hz = carrier.ssb_center_freq_hz;
// Calculate integer SSB to pointA frequency offset in Hz // Calculate integer SSB to pointA frequency offset in Hz
uint32_t ssb_pointA_freq_offset_Hz = uint32_t ssb_pointA_freq_offset_Hz =
(ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0;
// derive coreset0 parameters // derive coreset0 parameters
if (srsran_coreset_zero(carrier.pci, ssb_pointA_freq_offset_Hz, carrier.scs, carrier.scs, coreset0_idx, coreset) != if (srsran_coreset_zero(carrier.pci, ssb_pointA_freq_offset_Hz, carrier.scs, carrier.scs, coreset0_idx, coreset) !=
@ -373,7 +388,31 @@ int main(int argc, char** argv)
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
coreset->freq_resources[i] = i < coreset_n_rb / 6; coreset->freq_resources[i] = i < coreset_n_rb / 6;
} }
pdsch_hl_cfg.nof_common_time_ra = 1; if (interleaved_pdcch) {
coreset->mapping_type = srsran_coreset_mapping_type_interleaved;
coreset->reg_bundle_size = srsran_coreset_bundle_size_n6;
coreset->interleaver_size = srsran_coreset_bundle_size_n2;
coreset->precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
coreset->shift_index = carrier.pci;
}
// set coreset0 bandwidth (it is used in RA when ss_type = common3)
dci_cfg.coreset0_bw = coreset_n_rb;
// SCH configuration parameters
if (pdsch_time_ra_start >= 0 && pdsch_time_ra_length >= 0) {
auto last_pdsch_symbol = (uint16_t)(pdsch_time_ra_start + pdsch_time_ra_length);
if (last_pdsch_symbol > SRSRAN_NSYMB_PER_SLOT_NR) {
ERROR("incorrect PDSCH start symbol or length provided");
return clean_exit(ret);
}
uint32_t sliv = srsran_ra_nr_type1_riv(SRSRAN_NSYMB_PER_SLOT_NR, pdsch_time_ra_start, pdsch_time_ra_length);
pdsch_hl_cfg.nof_dedicated_time_ra = 1;
pdsch_hl_cfg.dedicated_time_ra[0].mapping_type = srsran_sch_mapping_type_A;
pdsch_hl_cfg.dedicated_time_ra[0].k = 0;
pdsch_hl_cfg.dedicated_time_ra[0].sliv = sliv;
}
} }
char coreset_info[512] = {}; char coreset_info[512] = {};

@ -30,10 +30,14 @@
#include <stdlib.h> #include <stdlib.h>
// NR parameters // NR parameters
static uint32_t pci = 1; // Physical Cell Identifier static uint32_t pci = 500; // Physical Cell Identifier
static uint32_t carrier_nof_prb = 52; // Carrier bandwidth static uint32_t carrier_nof_prb = 52; // Carrier bandwidth
static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static double center_frequency_hz = 3.5e9;
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_15kHz;
static double ssb_frequency_hz = 3.5e9 - 960e3;
static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_C;
static srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_TDD;
// Test and channel parameters // Test and channel parameters
static uint32_t nof_sf = 1000; // Number of subframes to test static uint32_t nof_sf = 1000; // Number of subframes to test
@ -44,7 +48,7 @@ static float delay_max_us = 1000.0f; // Maximum dynamic delay in microsecon
static float delay_period_s = 60.0f; // Delay period in seconds static float delay_period_s = 60.0f; // Delay period in seconds
// Test context // Test context
static double srate_hz = 0.0f; // Base-band sampling rate static double srate_hz = 0.0; // Base-band sampling rate
static uint32_t sf_len = 0; // Subframe length static uint32_t sf_len = 0; // Subframe length
static cf_t* buffer = NULL; // Base-band buffer static cf_t* buffer = NULL; // Base-band buffer
static cf_t* buffer2 = NULL; // Base-band buffer static cf_t* buffer2 = NULL; // Base-band buffer
@ -108,7 +112,7 @@ static int test_context_init(test_context_t* ctx)
srsran_ssb_args_t ssb_args = {}; srsran_ssb_args_t ssb_args = {};
ssb_args.max_srate_hz = srate_hz; ssb_args.max_srate_hz = srate_hz;
ssb_args.min_scs = carrier_scs; ssb_args.min_scs = ssb_scs;
ssb_args.enable_encode = true; ssb_args.enable_encode = true;
if (srsran_ssb_init(&ctx->ssb, &ssb_args) < SRSRAN_SUCCESS) { if (srsran_ssb_init(&ctx->ssb, &ssb_args) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -117,10 +121,11 @@ static int test_context_init(test_context_t* ctx)
srsran_ssb_cfg_t ssb_cfg = {}; srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srate_hz; ssb_cfg.srate_hz = srate_hz;
ssb_cfg.srate_hz = srate_hz; ssb_cfg.srate_hz = srate_hz;
ssb_cfg.center_freq_hz = 3.5e9; ssb_cfg.center_freq_hz = center_frequency_hz;
ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3; ssb_cfg.ssb_freq_hz = ssb_frequency_hz;
ssb_cfg.scs = ssb_scs; ssb_cfg.scs = ssb_scs;
ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C; ssb_cfg.pattern = ssb_pattern;
ssb_cfg.duplex_mode = duplex_mode;
if (srsran_ssb_set_cfg(&ctx->ssb, &ssb_cfg) < SRSRAN_SUCCESS) { if (srsran_ssb_set_cfg(&ctx->ssb, &ssb_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -250,10 +255,12 @@ int main(int argc, char** argv)
int ret = SRSRAN_ERROR; int ret = SRSRAN_ERROR;
parse_args(argc, argv); parse_args(argc, argv);
srate_hz = (double)SRSRAN_SUBC_SPACING_NR(carrier_scs) * srsran_min_symbol_sz_rb(carrier_nof_prb); if (!isnormal(srate_hz)) {
sf_len = (uint32_t)ceil(srate_hz / 1000.0); srate_hz = (double)SRSRAN_SUBC_SPACING_NR(carrier_scs) * srsran_min_symbol_sz_rb(carrier_nof_prb);
buffer = srsran_vec_cf_malloc(sf_len); }
buffer2 = srsran_vec_cf_malloc(sf_len); sf_len = (uint32_t)ceil(srate_hz / 1000.0);
buffer = srsran_vec_cf_malloc(sf_len);
buffer2 = srsran_vec_cf_malloc(sf_len);
test_context_t ctx = {}; test_context_t ctx = {};
srsran_ue_sync_nr_t ue_sync = {}; srsran_ue_sync_nr_t ue_sync = {};
@ -273,7 +280,7 @@ int main(int argc, char** argv)
ue_sync_args.min_scs = carrier_scs; ue_sync_args.min_scs = carrier_scs;
ue_sync_args.recv_obj = &ctx; ue_sync_args.recv_obj = &ctx;
ue_sync_args.recv_callback = &recv_callback; ue_sync_args.recv_callback = &recv_callback;
ue_sync_args.disable_cfo = false; ue_sync_args.disable_cfo = true;
if (srsran_ue_sync_nr_init(&ue_sync, &ue_sync_args) < SRSRAN_SUCCESS) { if (srsran_ue_sync_nr_init(&ue_sync, &ue_sync_args) < SRSRAN_SUCCESS) {
ERROR("Init"); ERROR("Init");
goto clean_exit; goto clean_exit;
@ -281,10 +288,11 @@ int main(int argc, char** argv)
srsran_ue_sync_nr_cfg_t ue_sync_cfg = {}; srsran_ue_sync_nr_cfg_t ue_sync_cfg = {};
ue_sync_cfg.ssb.srate_hz = srate_hz; ue_sync_cfg.ssb.srate_hz = srate_hz;
ue_sync_cfg.ssb.center_freq_hz = 3.5e9; ue_sync_cfg.ssb.center_freq_hz = center_frequency_hz;
ue_sync_cfg.ssb.ssb_freq_hz = 3.5e9 - 960e3; ue_sync_cfg.ssb.ssb_freq_hz = ssb_frequency_hz;
ue_sync_cfg.ssb.scs = ssb_scs; ue_sync_cfg.ssb.scs = ssb_scs;
ue_sync_cfg.ssb.pattern = SRSRAN_SSB_PATTERN_C; ue_sync_cfg.ssb.pattern = ssb_pattern;
ue_sync_cfg.ssb.duplex_mode = duplex_mode;
ue_sync_cfg.N_id = pci; ue_sync_cfg.N_id = pci;
if (srsran_ue_sync_nr_set_cfg(&ue_sync, &ue_sync_cfg) < SRSRAN_SUCCESS) { if (srsran_ue_sync_nr_set_cfg(&ue_sync, &ue_sync_cfg) < SRSRAN_SUCCESS) {
ERROR("Init"); ERROR("Init");
@ -316,4 +324,4 @@ clean_exit:
test_context_free(&ctx); test_context_free(&ctx);
return ret; return ret;
} }

@ -129,19 +129,12 @@ static void ue_sync_nr_apply_feedback(srsran_ue_sync_nr_t* q)
ue_sync_nr_reset_feedback(q); ue_sync_nr_reset_feedback(q);
} }
static int ue_sync_nr_run_find(srsran_ue_sync_nr_t* q, cf_t* buffer) static int ue_sync_nr_update_ssb(srsran_ue_sync_nr_t* q,
const srsran_csi_trs_measurements_t* measurements,
const srsran_pbch_msg_nr_t* pbch_msg)
{ {
srsran_csi_trs_measurements_t measurements = {}; srsran_mib_nr_t mib = {};
srsran_pbch_msg_nr_t pbch_msg = {}; if (srsran_pbch_msg_nr_mib_unpack(pbch_msg, &mib) != SRSRAN_SUCCESS) {
// Find SSB, measure PSS/SSS and decode PBCH
if (srsran_ssb_find(&q->ssb, buffer, q->N_id, &measurements, &pbch_msg) < SRSRAN_SUCCESS) {
ERROR("Error finding SSB");
return SRSRAN_ERROR;
}
// If the PBCH message was NOT decoded, early return
if (!pbch_msg.crc) {
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -149,24 +142,43 @@ static int ue_sync_nr_run_find(srsran_ue_sync_nr_t* q, cf_t* buffer)
ue_sync_nr_reset_feedback(q); ue_sync_nr_reset_feedback(q);
// Set feedback measurement // Set feedback measurement
srsran_combine_csi_trs_measurements(&q->feedback, &measurements, &q->feedback); srsran_combine_csi_trs_measurements(&q->feedback, measurements, &q->feedback);
// Apply feedback // Apply feedback
ue_sync_nr_apply_feedback(q); ue_sync_nr_apply_feedback(q);
// Setup context // Setup context
q->ssb_idx = pbch_msg.ssb_idx; q->ssb_idx = pbch_msg->ssb_idx;
q->sf_idx = srsran_ssb_candidate_sf_idx(&q->ssb, pbch_msg.ssb_idx, pbch_msg.hrf); q->sf_idx = srsran_ssb_candidate_sf_idx(&q->ssb, pbch_msg->ssb_idx, pbch_msg->hrf);
q->sfn = pbch_msg.sfn_4lsb; q->sfn = mib.sfn;
// Transition to track only if the measured delay is below 2.4 microseconds // Transition to track only if the measured delay is below 2.4 microseconds
if (measurements.delay_us < 2.4f) { if (measurements->delay_us < 2.4f) {
q->state = SRSRAN_UE_SYNC_NR_STATE_TRACK; q->state = SRSRAN_UE_SYNC_NR_STATE_TRACK;
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static int ue_sync_nr_run_find(srsran_ue_sync_nr_t* q, cf_t* buffer)
{
srsran_csi_trs_measurements_t measurements = {};
srsran_pbch_msg_nr_t pbch_msg = {};
// Find SSB, measure PSS/SSS and decode PBCH
if (srsran_ssb_find(&q->ssb, buffer, q->N_id, &measurements, &pbch_msg) < SRSRAN_SUCCESS) {
ERROR("Error finding SSB");
return SRSRAN_ERROR;
}
// If the PBCH message was NOT decoded, early return
if (!pbch_msg.crc) {
return SRSRAN_SUCCESS;
}
return ue_sync_nr_update_ssb(q, &measurements, &pbch_msg);
}
static int ue_sync_nr_run_track(srsran_ue_sync_nr_t* q, cf_t* buffer) static int ue_sync_nr_run_track(srsran_ue_sync_nr_t* q, cf_t* buffer)
{ {
srsran_csi_trs_measurements_t measurements = {}; srsran_csi_trs_measurements_t measurements = {};
@ -176,28 +188,29 @@ static int ue_sync_nr_run_track(srsran_ue_sync_nr_t* q, cf_t* buffer)
// Check if the SSB selected candidate index shall be received in this subframe // Check if the SSB selected candidate index shall be received in this subframe
bool is_ssb_opportunity = (q->sf_idx == srsran_ssb_candidate_sf_idx(&q->ssb, q->ssb_idx, half_frame > 0)); bool is_ssb_opportunity = (q->sf_idx == srsran_ssb_candidate_sf_idx(&q->ssb, q->ssb_idx, half_frame > 0));
// If // Use SSB periodicity
if (is_ssb_opportunity) { if (q->ssb.cfg.periodicity_ms >= 10) {
// Measure PSS/SSS and decode PBCH // SFN match with the periodicity
if (srsran_ssb_track(&q->ssb, buffer, q->N_id, q->ssb_idx, half_frame, &measurements, &pbch_msg) < SRSRAN_SUCCESS) { is_ssb_opportunity = is_ssb_opportunity && (half_frame == 0) && (q->sfn % q->ssb.cfg.periodicity_ms / 10 == 0);
ERROR("Error finding SSB"); }
return SRSRAN_ERROR;
}
// If the PBCH message was NOT decoded, transition to track if (!is_ssb_opportunity) {
if (!pbch_msg.crc) { return SRSRAN_SUCCESS;
q->state = SRSRAN_UE_SYNC_NR_STATE_FIND; }
return SRSRAN_SUCCESS;
}
// Otherwise feedback measurements and apply // Measure PSS/SSS and decode PBCH
srsran_combine_csi_trs_measurements(&q->feedback, &measurements, &q->feedback); if (srsran_ssb_track(&q->ssb, buffer, q->N_id, q->ssb_idx, half_frame, &measurements, &pbch_msg) < SRSRAN_SUCCESS) {
ERROR("Error finding SSB");
return SRSRAN_ERROR;
} }
// Apply accumulated feedback // If the PBCH message was NOT decoded, transition to find
ue_sync_nr_apply_feedback(q); if (!pbch_msg.crc) {
q->state = SRSRAN_UE_SYNC_NR_STATE_FIND;
return SRSRAN_SUCCESS;
}
return SRSRAN_SUCCESS; return ue_sync_nr_update_ssb(q, &measurements, &pbch_msg);
} }
static int ue_sync_nr_recv(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_timestamp_t* timestamp) static int ue_sync_nr_recv(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_timestamp_t* timestamp)
@ -247,7 +260,7 @@ static int ue_sync_nr_recv(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_timesta
// Compensate CFO // Compensate CFO
for (uint32_t chan = 0; chan < q->nof_rx_channels; chan++) { for (uint32_t chan = 0; chan < q->nof_rx_channels; chan++) {
if (buffer[chan] != 0 && !q->disable_cfo) { if (buffer[chan] != 0 && !q->disable_cfo) {
srsran_vec_apply_cfo(buffer[chan], q->cfo_hz / q->srate_hz, buffer[chan], (int)q->sf_sz); srsran_vec_apply_cfo(buffer[chan], -q->cfo_hz / q->srate_hz, buffer[chan], (int)q->sf_sz);
} }
} }

@ -470,6 +470,7 @@ int rlc::add_bearer_mrb(uint32_t lcid)
logger.error("Error configuring RLC entity."); logger.error("Error configuring RLC entity.");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
rlc_entity->set_bsr_callback(bsr_callback);
if (rlc_array_mrb.count(lcid) == 0) { if (rlc_array_mrb.count(lcid) == 0) {
if (not rlc_array_mrb.insert(rlc_map_pair_t(lcid, std::move(rlc_entity))).second) { if (not rlc_array_mrb.insert(rlc_map_pair_t(lcid, std::move(rlc_entity))).second) {
logger.error("Error inserting RLC entity in to array."); logger.error("Error inserting RLC entity in to array.");

@ -47,7 +47,7 @@ rlc_am::rlc_am(srsran_rat_t rat,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_) : srsran::timer_handler* timers_) :
logger(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_) rlc_common(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_)
{ {
if (rat == srsran_rat_t::lte) { if (rat == srsran_rat_t::lte) {
rlc_am_lte_tx* tx = new rlc_am_lte_tx(this); rlc_am_lte_tx* tx = new rlc_am_lte_tx(this);
@ -64,49 +64,49 @@ rlc_am::rlc_am(srsran_rat_t rat,
tx->set_rx(rx); tx->set_rx(rx);
rx->set_tx(tx); rx->set_tx(tx);
} else { } else {
logger.error("Invalid RAT at entity initialization"); RlcError("Invalid RAT at entity initialization");
} }
} }
bool rlc_am::configure(const rlc_config_t& cfg_) bool rlc_am::configure(const rlc_config_t& cfg_)
{ {
// determine bearer name and configure Rx/Tx objects // determine bearer name and configure rx/tx objects
rb_name = rrc->get_rb_name(lcid); rb_name = rrc->get_rb_name(lcid);
// store config // store configuration
cfg = cfg_; cfg = cfg_;
if (not rx_base->configure(cfg)) { if (not rx_base->configure(cfg)) {
logger.error("Error configuring bearer (RX)"); RlcError("Error configuring bearer (RX)");
return false; return false;
} }
if (not tx_base->configure(cfg)) { if (not tx_base->configure(cfg)) {
logger.error("Error configuring bearer (TX)"); RlcError("Error configuring bearer (TX)");
return false; return false;
} }
logger.info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " RlcInfo("configured - t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
"t_reordering=%d, t_status_prohibit=%d", "t_reordering=%d, t_status_prohibit=%d",
rb_name.c_str(), cfg.am.t_poll_retx,
cfg.am.t_poll_retx, cfg.am.poll_pdu,
cfg.am.poll_pdu, cfg.am.poll_byte,
cfg.am.poll_byte, cfg.am.max_retx_thresh,
cfg.am.max_retx_thresh, cfg.am.t_reordering,
cfg.am.t_reordering, cfg.am.t_status_prohibit);
cfg.am.t_status_prohibit);
return true; return true;
} }
void rlc_am::stop() void rlc_am::stop()
{ {
logger.debug("Stopped bearer %s", rb_name.c_str()); RlcDebug("Stopped bearer");
tx_base->stop(); tx_base->stop();
rx_base->stop(); rx_base->stop();
} }
void rlc_am::reestablish() void rlc_am::reestablish()
{ {
logger.debug("Reestablished bearer %s", rb_name.c_str()); RlcDebug("Reestablished bearer");
tx_base->reestablish(); // calls stop and enables tx again tx_base->reestablish(); // calls stop and enables tx again
rx_base->reestablish(); // calls only stop rx_base->reestablish(); // calls only stop
} }
@ -207,7 +207,7 @@ void rlc_am::set_bsr_callback(bsr_callback_t callback)
/******************************************************* /*******************************************************
* RLC AM TX entity * RLC AM TX entity
* This class is used for common code between the * This class is used for common code between the
* LTE and NR TX entitites * LTE and NR TX entities
*******************************************************/ *******************************************************/
int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu) int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu)
{ {
@ -218,7 +218,7 @@ int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu)
} }
if (sdu.get() == nullptr) { if (sdu.get() == nullptr) {
logger->warning("NULL SDU pointer in write_sdu()"); RlcWarning("NULL SDU pointer in write_sdu()");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -230,15 +230,14 @@ int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu)
uint32_t nof_bytes = sdu->N_bytes; uint32_t nof_bytes = sdu->N_bytes;
srsran::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu)); srsran::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu));
if (ret) { if (ret) {
logger->info(msg_ptr, nof_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rb_name, nof_bytes, tx_sdu_queue.size()); RlcHexInfo(msg_ptr, nof_bytes, "Tx SDU (%d B, tx_sdu_queue_len=%d)", nof_bytes, tx_sdu_queue.size());
} else { } else {
// in case of fail, the try_write returns back the sdu // in case of fail, the try_write returns back the sdu
logger->warning(ret.error()->msg, RlcHexWarning(ret.error()->msg,
ret.error()->N_bytes, ret.error()->N_bytes,
"[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", "[Dropped SDU] Tx SDU (%d B, tx_sdu_queue_len=%d)",
rb_name, ret.error()->N_bytes,
ret.error()->N_bytes, tx_sdu_queue.size());
tx_sdu_queue.size());
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -253,11 +252,11 @@ void rlc_am::rlc_am_base_tx::set_bsr_callback(bsr_callback_t callback)
/******************************************************* /*******************************************************
* RLC AM RX entity * RLC AM RX entity
* This class is used for common code between the * This class is used for common code between the
* LTE and NR TX entitites * LTE and NR TX entities
*******************************************************/ *******************************************************/
void rlc_am::rlc_am_base_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes) void rlc_am::rlc_am_base_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes)
{ {
logger->info("Rx PDU -- N bytes %d", nof_bytes); RlcInfo("Rx PDU - N bytes %d", nof_bytes);
if (nof_bytes < 1) { if (nof_bytes < 1) {
return; return;
} }

File diff suppressed because it is too large Load Diff

@ -318,32 +318,4 @@ bool rlc_am_not_start_aligned(const uint8_t fi)
return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED); return (fi == RLC_FI_FIELD_NOT_START_ALIGNED || fi == RLC_FI_FIELD_NOT_START_OR_END_ALIGNED);
} }
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header)
{
if (not log_ch.enabled()) {
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer,
"[{}, RF={}, P={}, FI={}, SN={}, LSF={}, SO={}, N_li={}",
rlc_dc_field_text[header.dc],
(header.rf ? "1" : "0"),
(header.p ? "1" : "0"),
(header.fi ? "1" : "0"),
header.sn,
(header.lsf ? "1" : "0"),
header.so,
header.N_li);
if (header.N_li > 0) {
fmt::format_to(buffer, " ({}", header.li[0]);
for (uint32_t i = 1; i < header.N_li; ++i) {
fmt::format_to(buffer, ", {}", header.li[i]);
}
fmt::format_to(buffer, ")");
}
fmt::format_to(buffer, "]");
log_ch("%s", to_c_str(buffer));
}
} // namespace srsran } // namespace srsran

@ -32,6 +32,7 @@
namespace srsran { namespace srsran {
const static uint32_t max_tx_queue_size = 256;
/**************************************************************************** /****************************************************************************
* RLC AM NR entity * RLC AM NR entity
***************************************************************************/ ***************************************************************************/
@ -39,30 +40,33 @@ namespace srsran {
/*************************************************************************** /***************************************************************************
* Tx subclass implementation * Tx subclass implementation
***************************************************************************/ ***************************************************************************/
rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(&parent_->logger) {} rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(parent_->logger) {}
bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_) bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_)
{ {
cfg = cfg_.am_nr; cfg = cfg_.am_nr;
rb_name = parent->rb_name;
if (cfg.tx_sn_field_length != rlc_am_nr_sn_size_t::size12bits) { if (cfg.tx_sn_field_length != rlc_am_nr_sn_size_t::size12bits) {
logger->warning("RLC AM NR only supporst 12 bit SN length."); RlcWarning("RLC AM NR only supports 12 bit SN length.");
return false; return false;
} }
/* if (cfg_.tx_queue_length > max_tx_queue_size) {
if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) { RlcError("configuring tx queue length of %d PDUs too big. Maximum value is %d.",
logger.error("Configuring Tx queue length of %d PDUs too big. Maximum value is %d.", cfg_.tx_queue_length,
cfg_.tx_queue_length, max_tx_queue_size);
MAX_SDUS_PER_RLC_PDU); return false;
return false; }
}
*/
mod_nr = (cfg.tx_sn_field_length == rlc_am_nr_sn_size_t::size12bits) ? 4096 : 262144; mod_nr = cfg.tx_sn_field_length == rlc_am_nr_sn_size_t::size12bits ? 4096 : 262144;
min_hdr_size = cfg.tx_sn_field_length == rlc_am_nr_sn_size_t::size12bits ? 2 : 3;
max_hdr_size = min_hdr_size + so_size;
tx_enabled = true; tx_enabled = true;
RlcDebug("RLC AM NR tx entity configured.");
return true; return true;
} }
@ -74,38 +78,33 @@ bool rlc_am_nr_tx::has_data()
uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
{ {
logger->debug("MAC opportunity - %d bytes", nof_bytes);
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
if (not tx_enabled) { if (not tx_enabled) {
logger->debug("RLC entity not active. Not generating PDU."); RlcDebug("RLC entity not active. Not generating PDU.");
return 0; return 0;
} }
// logger.debug("tx_window size - %zu PDUs", tx_window.size()); RlcDebug("MAC opportunity - bytes=%d, tx_window size=%zu PDUs", nof_bytes, tx_window.size());
// Tx STATUS if requested // Tx STATUS if requested
if (do_status()) { if (do_status()) {
unique_byte_buffer_t tx_pdu = srsran::make_byte_buffer(); unique_byte_buffer_t tx_pdu = srsran::make_byte_buffer();
if (tx_pdu == nullptr) { if (tx_pdu == nullptr) {
logger->error("Couldn't allocate PDU in %s().", __FUNCTION__); RlcError("couldn't allocate PDU in %s().", __FUNCTION__);
return 0; return 0;
} }
build_status_pdu(tx_pdu.get(), nof_bytes); build_status_pdu(tx_pdu.get(), nof_bytes);
memcpy(payload, tx_pdu->msg, tx_pdu->N_bytes); memcpy(payload, tx_pdu->msg, tx_pdu->N_bytes);
logger->debug("Status PDU built - %d bytes", tx_pdu->N_bytes); RlcDebug("status PDU built - %d bytes", tx_pdu->N_bytes);
return tx_pdu->N_bytes; return tx_pdu->N_bytes;
} }
// Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU // Retransmit if required
// TODO
// RETX if required
if (not retx_queue.empty()) { if (not retx_queue.empty()) {
logger->info("Retx required. Retx queue size: %d", retx_queue.size()); RlcInfo("re-transmission required. Retransmission queue size: %d", retx_queue.size());
unique_byte_buffer_t tx_pdu = srsran::make_byte_buffer(); unique_byte_buffer_t tx_pdu = srsran::make_byte_buffer();
if (tx_pdu == nullptr) { if (tx_pdu == nullptr) {
logger->error("Couldn't allocate PDU in %s().", __FUNCTION__); RlcError("couldn't allocate PDU in %s().", __FUNCTION__);
return 0; return 0;
} }
int retx_err = build_retx_pdu(tx_pdu, nof_bytes); int retx_err = build_retx_pdu(tx_pdu, nof_bytes);
@ -115,25 +114,34 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
} }
} }
// Read new SDU from TX queue // Send remaining segment, if it exists
if (sdu_under_segmentation.rlc_sn != INVALID_RLC_SN) {
if (not tx_window.has_sn(sdu_under_segmentation.rlc_sn)) {
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
RlcError("SDU currently being segmented does not exist in tx_window. Aborting segmentation SN=%d",
sdu_under_segmentation.rlc_sn);
return 0;
}
return build_continuation_sdu_segment(tx_window[sdu_under_segmentation.rlc_sn], payload, nof_bytes);
}
// Check whether there is something to TX
if (tx_sdu_queue.is_empty()) { if (tx_sdu_queue.is_empty()) {
logger->info("No data available to be sent"); RlcInfo("no data available to be sent");
return 0; return 0;
} }
// Read new SDU from TX queue
unique_byte_buffer_t tx_sdu; unique_byte_buffer_t tx_sdu;
logger->debug("Reading from RLC SDU queue. Queue size %d", tx_sdu_queue.size()); RlcDebug("reading from RLC SDU queue. Queue size %d", tx_sdu_queue.size());
do { do {
tx_sdu = tx_sdu_queue.read(); tx_sdu = tx_sdu_queue.read();
} while (tx_sdu == nullptr && tx_sdu_queue.size() != 0); } while (tx_sdu == nullptr && tx_sdu_queue.size() != 0);
if (tx_sdu != nullptr) { if (tx_sdu != nullptr) {
logger->debug("Read RLC SDU - %d bytes", tx_sdu->N_bytes); RlcDebug("read RLC SDU - %d bytes", tx_sdu->N_bytes);
} } else {
RlcDebug("no SDUs left in the tx queue.");
uint16_t hdr_size = 2;
if (tx_sdu->N_bytes + hdr_size > nof_bytes) {
logger->warning("Segmentation not supported yet");
return 0; return 0;
} }
@ -142,10 +150,16 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
rlc_amd_tx_pdu_nr& tx_pdu = tx_window.add_pdu(st.tx_next); rlc_amd_tx_pdu_nr& tx_pdu = tx_window.add_pdu(st.tx_next);
tx_pdu.buf = srsran::make_byte_buffer(); tx_pdu.buf = srsran::make_byte_buffer();
if (tx_pdu.buf == nullptr) { if (tx_pdu.buf == nullptr) {
logger->error("Couldn't allocate PDU in %s().", __FUNCTION__); RlcError("couldn't allocate PDU in %s().", __FUNCTION__);
return 0; return 0;
} }
// Segment new SDU if necessary
if (tx_sdu->N_bytes + min_hdr_size > nof_bytes) {
RlcInfo("trying to build PDU segment from SDU.");
return build_new_sdu_segment(std::move(tx_sdu), tx_pdu, payload, nof_bytes);
}
memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes); memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes);
tx_pdu.buf->N_bytes = tx_sdu->N_bytes; tx_pdu.buf->N_bytes = tx_sdu->N_bytes;
@ -157,28 +171,183 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
hdr.sn_size = rlc_am_nr_sn_size_t::size12bits; hdr.sn_size = rlc_am_nr_sn_size_t::size12bits;
hdr.sn = st.tx_next; hdr.sn = st.tx_next;
tx_pdu.header = hdr; tx_pdu.header = hdr;
log_rlc_am_nr_pdu_header_to_string(logger->info, hdr); log_rlc_am_nr_pdu_header_to_string(logger.info, hdr);
// Write header // Write header
uint32_t len = rlc_am_nr_write_data_pdu_header(hdr, tx_sdu.get()); uint32_t len = rlc_am_nr_write_data_pdu_header(hdr, tx_sdu.get());
if (len > nof_bytes) { if (len > nof_bytes) {
logger->error("Error writing AMD PDU header"); RlcError("error writing AMD PDU header");
} }
// Update TX Next // Update TX Next
st.tx_next = (st.tx_next + 1) % MOD; st.tx_next = (st.tx_next + 1) % MOD;
memcpy(payload, tx_sdu->msg, tx_sdu->N_bytes); memcpy(payload, tx_sdu->msg, tx_sdu->N_bytes);
logger->debug("Wrote RLC PDU - %d bytes", tx_sdu->N_bytes); RlcDebug("wrote RLC PDU - %d bytes", tx_sdu->N_bytes);
return tx_sdu->N_bytes; return tx_sdu->N_bytes;
} }
int rlc_am_nr_tx::build_new_sdu_segment(unique_byte_buffer_t tx_sdu,
rlc_amd_tx_pdu_nr& tx_pdu,
uint8_t* payload,
uint32_t nof_bytes)
{
RlcInfo("creating new SDU segment. Tx SDU (%d B), nof_bytes=%d B ", tx_sdu->N_bytes, nof_bytes);
// Sanity check: can this SDU be sent this in a single PDU?
if ((tx_sdu->N_bytes + min_hdr_size) < nof_bytes) {
RlcError("calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU. Tx SDU (%d B), "
"nof_bytes=%d B ",
tx_sdu->N_bytes,
nof_bytes);
return 0;
}
// Sanity check: can this SDU be sent considering header overhead?
if (nof_bytes <= min_hdr_size) { // Small header as SO is not present
RlcError("cannot build new sdu_segment, there are not enough bytes allocated to tx header plus data. nof_bytes=%d",
nof_bytes);
return 0;
}
// Prepare header
rlc_am_nr_pdu_header_t hdr = {};
hdr.dc = RLC_DC_FIELD_DATA_PDU;
hdr.p = get_pdu_poll();
hdr.si = rlc_nr_si_field_t::first_segment;
hdr.sn_size = rlc_am_nr_sn_size_t::size12bits;
hdr.sn = st.tx_next;
hdr.so = 0;
tx_pdu.header = hdr;
log_rlc_am_nr_pdu_header_to_string(logger.info, hdr);
// Write header
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(hdr, payload);
if (hdr_len >= nof_bytes || hdr_len != min_hdr_size) {
RlcError("error writing AMD PDU header");
return 0;
}
// Copy PDU to payload
uint32_t segment_payload_len = nof_bytes - hdr_len;
srsran_assert((hdr_len + segment_payload_len) <= nof_bytes, "Error calculating hdr_len and segment_payload_len");
memcpy(&payload[hdr_len], tx_pdu.buf->msg, segment_payload_len);
// Save SDU currently being segmented
sdu_under_segmentation.rlc_sn = st.tx_next;
sdu_under_segmentation.buf = std::move(tx_sdu);
// Store Segment Info
rlc_amd_tx_pdu_nr::pdu_segment segment_info;
segment_info.payload_len = segment_payload_len;
tx_pdu.segment_list.push_back(segment_info);
return hdr_len + segment_payload_len;
}
int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes)
{
RlcInfo("continuing SDU segment. SN=%d, Tx SDU (%d B), nof_bytes=%d B ",
sdu_under_segmentation.rlc_sn,
sdu_under_segmentation.buf->N_bytes,
nof_bytes);
// Sanity check: is there an initial SDU segment?
if (tx_pdu.segment_list.empty()) {
RlcError("build_continuation_sdu_segment was called, but there was no initial segment. SN=%d, Tx SDU (%d B), "
"nof_bytes=%d B ",
sdu_under_segmentation.rlc_sn,
sdu_under_segmentation.buf->N_bytes,
nof_bytes);
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
sdu_under_segmentation.buf = nullptr;
return 0;
}
// Sanity check: can this SDU be sent considering header overhead?
if ((max_hdr_size + 1) < nof_bytes) { // Larger header size, as SO is present
RlcError("cannot build new sdu_segment, there are not enough bytes allocated to tx header plus data. nof_bytes=%d",
nof_bytes);
return 0;
}
// Can the rest of the SDU be sent on a single segment PDU?
const rlc_amd_tx_pdu_nr::pdu_segment& seg = tx_pdu.segment_list.back();
uint32_t last_byte = seg.so + seg.payload_len;
RlcDebug("continuing SDU segment. SN=%d, last byte transmitted %d", tx_pdu.rlc_sn, last_byte);
// Sanity check: last byte must be smaller than SDU
if (sdu_under_segmentation.buf->N_bytes < last_byte) {
RlcError("last byte transmitted larger than SDU len. SDU len=%d B, last_byte=%d B", tx_pdu.buf->N_bytes, last_byte);
return 0;
}
uint32_t segment_payload_full_len = sdu_under_segmentation.buf->N_bytes - last_byte + max_hdr_size; // SO is included
uint32_t segment_payload_len = sdu_under_segmentation.buf->N_bytes - last_byte;
rlc_nr_si_field_t si = {};
if (segment_payload_full_len > nof_bytes) {
RlcInfo("grant is not large enough for full SDU. "
"SDU bytes left %d, nof_bytes %d, ",
segment_payload_full_len,
nof_bytes);
si = rlc_nr_si_field_t::neither_first_nor_last_segment;
segment_payload_len = nof_bytes - max_hdr_size;
segment_payload_full_len = nof_bytes;
} else {
RlcInfo("grant is large enough for full SDU."
"SDU bytes left %d, nof_bytes %d, ",
segment_payload_full_len,
nof_bytes);
si = rlc_nr_si_field_t::last_segment;
}
// Prepare header
rlc_am_nr_pdu_header_t hdr = {};
hdr.dc = RLC_DC_FIELD_DATA_PDU;
hdr.p = get_pdu_poll();
hdr.si = si;
hdr.sn_size = rlc_am_nr_sn_size_t::size12bits;
hdr.sn = st.tx_next;
hdr.so = last_byte;
tx_pdu.header = hdr;
log_rlc_am_nr_pdu_header_to_string(logger.info, hdr);
// Write header
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(hdr, payload);
if (hdr_len >= nof_bytes || hdr_len != max_hdr_size) {
RlcError("error writing AMD PDU header");
return 0;
}
// Copy PDU to payload
srsran_assert((hdr_len + segment_payload_len) <= nof_bytes, "Error calculating hdr_len and segment_payload_len");
memcpy(&payload[hdr_len], &tx_pdu.buf->msg[last_byte], segment_payload_len);
// Store PDU segment info into tx_window
rlc_amd_tx_pdu_nr::pdu_segment segment_info = {};
segment_info.so = last_byte;
segment_info.payload_len = segment_payload_len;
tx_pdu.segment_list.push_back(segment_info);
if (si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
RlcInfo("grant is not large enough for full SDU."
"Storing SDU segment info");
} else {
RlcInfo("grant is large enough for full SDU."
"Removing current SDU info");
sdu_under_segmentation.rlc_sn = INVALID_RLC_SN;
sdu_under_segmentation.buf = nullptr;
}
return hdr_len + segment_payload_len;
}
int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes) int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes)
{ {
// Check there is at least 1 element before calling front() // Check there is at least 1 element before calling front()
if (retx_queue.empty()) { if (retx_queue.empty()) {
logger->error("In build_retx_pdu(): retx_queue is empty"); RlcError("in build_retx_pdu(): retx_queue is empty");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -186,12 +355,12 @@ int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_byte
// Sanity check - drop any retx SNs not present in tx_window // Sanity check - drop any retx SNs not present in tx_window
while (not tx_window.has_sn(retx.sn)) { while (not tx_window.has_sn(retx.sn)) {
logger->warning("%s SN=%d not in Tx window. Ignoring retx.", parent->rb_name, retx.sn); RlcWarning("SN=%d not in tx window. Ignoring retx.", retx.sn);
retx_queue.pop(); retx_queue.pop();
if (!retx_queue.empty()) { if (!retx_queue.empty()) {
retx = retx_queue.front(); retx = retx_queue.front();
} else { } else {
logger->warning("%s empty retx queue, cannot provide retx PDU", parent->rb_name); RlcWarning("empty retx queue, cannot provide retx PDU");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
} }
@ -202,7 +371,7 @@ int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_byte
// Check if we exceed allocated number of bytes // Check if we exceed allocated number of bytes
if (hdr_len + tx_window[retx.sn].buf->N_bytes > nof_bytes) { if (hdr_len + tx_window[retx.sn].buf->N_bytes > nof_bytes) {
logger->warning("%s segmentation not supported yet. Cannot provide retx PDU", parent->rb_name); RlcWarning("segmentation not supported yet. Cannot provide retx PDU");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// TODO Consider re-segmentation // TODO Consider re-segmentation
@ -212,16 +381,15 @@ int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_byte
retx_queue.pop(); retx_queue.pop();
logger->info(tx_window[retx.sn].buf->msg, RlcHexInfo(tx_window[retx.sn].buf->msg,
tx_window[retx.sn].buf->N_bytes, tx_window[retx.sn].buf->N_bytes,
"%s Original SDU SN=%d (%d B) (attempt %d/%d)", "Original SDU SN=%d (%d B) (attempt %d/%d)",
parent->rb_name, retx.sn,
retx.sn, tx_window[retx.sn].buf->N_bytes,
tx_window[retx.sn].buf->N_bytes, tx_window[retx.sn].retx_count + 1,
tx_window[retx.sn].retx_count + 1, cfg.max_retx_thresh);
cfg.max_retx_thresh); RlcHexInfo(tx_pdu->msg, tx_pdu->N_bytes, "retx PDU SN=%d (%d B)", retx.sn, tx_pdu->N_bytes);
logger->info(tx_pdu->msg, tx_pdu->N_bytes, "%s ReTx PDU SN=%d (%d B)", parent->rb_name, retx.sn, tx_pdu->N_bytes); log_rlc_am_nr_pdu_header_to_string(logger.debug, new_header);
log_rlc_am_nr_pdu_header_to_string(logger->debug, new_header);
// debug_state(); // debug_state();
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -229,18 +397,18 @@ int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_byte
uint32_t rlc_am_nr_tx::build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes) uint32_t rlc_am_nr_tx::build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes)
{ {
logger->info("Generating Status PDU. Bytes available:%d", nof_bytes); RlcInfo("generating status PDU. Bytes available:%d", nof_bytes);
rlc_am_nr_status_pdu_t tx_status; rlc_am_nr_status_pdu_t tx_status;
int pdu_len = rx->get_status_pdu(&tx_status, nof_bytes); int pdu_len = rx->get_status_pdu(&tx_status, nof_bytes);
if (pdu_len == SRSRAN_ERROR) { if (pdu_len == SRSRAN_ERROR) {
logger->debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", rb_name); RlcDebug("deferred status PDU. Cause: Failed to acquire rx lock");
pdu_len = 0; pdu_len = 0;
} else if (pdu_len > 0 && nof_bytes >= static_cast<uint32_t>(pdu_len)) { } else if (pdu_len > 0 && nof_bytes >= static_cast<uint32_t>(pdu_len)) {
logger->debug("Generated Status PDU. Bytes:%d", pdu_len); RlcDebug("generated status PDU. Bytes:%d", pdu_len);
log_rlc_am_nr_status_pdu_to_string(logger->info, "%s Tx status PDU - %s", &tx_status, rb_name); log_rlc_am_nr_status_pdu_to_string(logger.info, "%s tx status PDU - %s", &tx_status, rb_name);
pdu_len = rlc_am_nr_write_status_pdu(tx_status, rlc_am_nr_sn_size_t::size12bits, payload); pdu_len = rlc_am_nr_write_status_pdu(tx_status, rlc_am_nr_sn_size_t::size12bits, payload);
} else { } else {
logger->info("%s Cannot tx status PDU - %d bytes available, %d bytes required", rb_name, nof_bytes, pdu_len); RlcInfo("cannot tx status PDU - %d bytes available, %d bytes required", nof_bytes, pdu_len);
pdu_len = 0; pdu_len = 0;
} }
@ -254,9 +422,9 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
} }
rlc_am_nr_status_pdu_t status = {}; rlc_am_nr_status_pdu_t status = {};
logger->debug(payload, nof_bytes, "%s Rx control PDU", parent->rb_name); RlcHexDebug(payload, nof_bytes, "%s Rx control PDU", parent->rb_name);
rlc_am_nr_read_status_pdu(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &status); rlc_am_nr_read_status_pdu(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &status);
log_rlc_am_nr_status_pdu_to_string(logger->info, "%s Rx Status PDU: %s", &status, parent->rb_name); log_rlc_am_nr_status_pdu_to_string(logger.info, "%s Rx Status PDU: %s", &status, parent->rb_name);
// Local variables for handling Status PDU will be updated with lock // Local variables for handling Status PDU will be updated with lock
/* /*
* - if the SN of the corresponding RLC SDU falls within the range * - if the SN of the corresponding RLC SDU falls within the range
@ -269,7 +437,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
? status.ack_sn ? status.ack_sn
: status.nacks[0].nack_sn - 1; // Stop processing ACKs at the first NACK, if it exists. : status.nacks[0].nack_sn - 1; // Stop processing ACKs at the first NACK, if it exists.
if (stop_sn > st.tx_next) { if (stop_sn > st.tx_next) {
logger->error("Rx'ed ACK or NACK larger than TX_NEXT. Ignoring status report"); RlcError("Received ACK or NACK larger than TX_NEXT. Ignoring status report");
return; return;
} }
for (uint32_t sn = st.tx_next_ack; sn < stop_sn; sn++) { for (uint32_t sn = st.tx_next_ack; sn < stop_sn; sn++) {
@ -278,7 +446,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
st.tx_next_ack = sn + 1; st.tx_next_ack = sn + 1;
// TODO notify PDCP // TODO notify PDCP
} else { } else {
logger->error("Missing ACKed SN from TX window"); RlcError("Missing ACKed SN from TX window");
break; break;
} }
} }
@ -329,35 +497,32 @@ uint32_t rlc_am_nr_tx::get_buffer_state()
void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_prio) void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_prio)
{ {
logger->debug("Buffer state requested, %s", rb_name);
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
RlcDebug("buffer state - do_status=%s", do_status() ? "yes" : "no");
logger->debug("%s Buffer state - do_status=%s", rb_name, do_status() ? "yes" : "no");
// Bytes needed for status report // Bytes needed for status report
if (do_status()) { if (do_status()) {
n_bytes_prio += rx->get_status_pdu_length(); n_bytes_prio += rx->get_status_pdu_length();
logger->debug("%s Buffer state - total status report: %d bytes", rb_name, n_bytes_prio); RlcDebug("buffer state - total status report: %d bytes", n_bytes_prio);
} }
// Bytes needed for retx // Bytes needed for retx
if (not retx_queue.empty()) { if (not retx_queue.empty()) {
rlc_amd_retx_t& retx = retx_queue.front(); rlc_amd_retx_t& retx = retx_queue.front();
logger->debug("%s Buffer state - retx - SN=%d, Segment: %s, %d:%d", RlcDebug("buffer state - retx - SN=%d, Segment: %s, %d:%d",
parent->rb_name, retx.sn,
retx.sn, retx.is_segment ? "true" : "false",
retx.is_segment ? "true" : "false", retx.so_start,
retx.so_start, retx.so_end);
retx.so_end);
if (tx_window.has_sn(retx.sn)) { if (tx_window.has_sn(retx.sn)) {
int req_bytes = retx.so_end - retx.so_start; int req_bytes = retx.so_end - retx.so_start;
int hdr_req_bytes = retx.is_segment ? 4 : 2; // Segmentation not supported yet int hdr_req_bytes = retx.is_segment ? max_hdr_size : min_hdr_size; // Segmentation not supported yet
if (req_bytes <= 0) { if (req_bytes <= 0) {
logger->error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn); RlcError("in get_buffer_state(): Removing retx with SN=%d from queue", retx.sn);
retx_queue.pop(); retx_queue.pop();
} else { } else {
n_bytes_prio += (req_bytes + hdr_req_bytes); n_bytes_prio += (req_bytes + hdr_req_bytes);
logger->debug("Buffer state - retx: %d bytes", n_bytes_prio); RlcDebug("buffer state - retx: %d bytes", n_bytes_prio);
} }
} }
} }
@ -367,11 +532,11 @@ void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_pri
n_bytes_new += tx_sdu_queue.size_bytes(); n_bytes_new += tx_sdu_queue.size_bytes();
// Room needed for fixed header of data PDUs // Room needed for fixed header of data PDUs
n_bytes_new += 2 * n_sdus; // TODO make header size configurable n_bytes_new += min_hdr_size * n_sdus;
logger->debug("%s Total buffer state - %d SDUs (%d B)", rb_name, n_sdus, n_bytes_new + n_bytes_prio); RlcDebug("total buffer state - %d SDUs (%d B)", n_sdus, n_bytes_new + n_bytes_prio);
if (bsr_callback) { if (bsr_callback) {
logger->debug("%s Calling BSR callback - %d new_tx, %d prio bytes", parent->rb_name, n_bytes_new, n_bytes_prio); RlcDebug("calling BSR callback - %d new_tx, %d priority bytes", n_bytes_new, n_bytes_prio);
bsr_callback(parent->lcid, n_bytes_new, n_bytes_prio); bsr_callback(parent->lcid, n_bytes_new, n_bytes_prio);
} }
} }
@ -432,13 +597,13 @@ rlc_am_nr_rx::rlc_am_nr_rx(rlc_am* parent_) :
pool(byte_buffer_pool::get_instance()), pool(byte_buffer_pool::get_instance()),
status_prohibit_timer(parent->timers->get_unique_timer()), status_prohibit_timer(parent->timers->get_unique_timer()),
reassembly_timer(parent->timers->get_unique_timer()), reassembly_timer(parent->timers->get_unique_timer()),
rlc_am_base_rx(parent_, &parent_->logger) rlc_am_base_rx(parent_, parent_->logger)
{} {}
bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_) bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_)
{ {
cfg = cfg_.am_nr; cfg = cfg_.am_nr;
rb_name = parent->rb_name;
// Configure status prohibit timer // Configure status prohibit timer
if (cfg.t_status_prohibit > 0) { if (cfg.t_status_prohibit > 0) {
status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit), status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit),
@ -448,10 +613,13 @@ bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_)
// Configure t_reassembly timer // Configure t_reassembly timer
if (cfg.t_reassembly > 0) { if (cfg.t_reassembly > 0) {
reassembly_timer.set(static_cast<uint32_t>(cfg.t_reassembly), [this](uint32_t timerid) { timer_expired(timerid); }); reassembly_timer.set(static_cast<uint32_t>(cfg.t_reassembly), [this](uint32_t timerid) { timer_expired(timerid); });
logger->info("Configured reassembly timer. t-Reassembly=%d ms", cfg.t_reassembly); RlcInfo("configured reassembly timer. t-Reassembly=%d ms", cfg.t_reassembly);
} }
mod_nr = (cfg.rx_sn_field_length == rlc_am_nr_sn_size_t::size12bits) ? 4096 : 262144; mod_nr = (cfg.rx_sn_field_length == rlc_am_nr_sn_size_t::size12bits) ? 4096 : 262144;
RlcDebug("RLC AM NR configured rx entity.");
return true; return true;
} }
@ -468,62 +636,37 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
rlc_am_nr_pdu_header_t header = {}; rlc_am_nr_pdu_header_t header = {};
uint32_t hdr_len = rlc_am_nr_read_data_pdu_header(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &header); uint32_t hdr_len = rlc_am_nr_read_data_pdu_header(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &header);
logger->info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", parent->rb_name, header.sn, nof_bytes); RlcHexInfo(payload, nof_bytes, "Rx data PDU SN=%d (%d B)", header.sn, nof_bytes);
log_rlc_am_nr_pdu_header_to_string(logger->debug, header); log_rlc_am_nr_pdu_header_to_string(logger.debug, header);
// Check wether SDU is within Rx Window // Check whether SDU is within Rx Window
if (!inside_rx_window(header.sn)) { if (!inside_rx_window(header.sn)) {
logger->info("%s SN=%d outside rx window [%d:%d] - discarding", RlcInfo("SN=%d outside rx window [%d:%d] - discarding", header.sn, st.rx_next, st.rx_next + RLC_AM_NR_WINDOW_SIZE);
parent->rb_name,
header.sn,
st.rx_next,
st.rx_next + RLC_AM_NR_WINDOW_SIZE);
return; return;
} }
// Section 5.2.3.2.2, discard duplicate PDUs // Section 5.2.3.2.2, discard duplicate PDUs
if (rx_window.has_sn(header.sn)) { if (rx_window.has_sn(header.sn) && rx_window[header.sn].fully_received) {
logger->info("%s Discarding duplicate SN=%d", parent->rb_name, header.sn); RlcInfo("discarding duplicate SN=%d", header.sn);
return; return;
} }
// Write to rx window // Write to rx window either full SDU or SDU segment
if (header.si == rlc_nr_si_field_t::full_sdu) { if (header.si == rlc_nr_si_field_t::full_sdu) {
// Full SDU received. Add SDU to Rx Window and copy full PDU into SDU buffer. int err = handle_full_data_sdu(header, payload, nof_bytes);
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.add_pdu(header.sn); if (err != SRSRAN_SUCCESS) {
rx_sdu.buf = srsran::make_byte_buffer();
if (rx_sdu.buf == nullptr) {
logger->error("Fatal Error: Couldn't allocate PDU in %s.", __FUNCTION__);
rx_window.remove_pdu(header.sn);
return;
}
rx_sdu.buf->set_timestamp();
// check available space for payload
if (nof_bytes > rx_sdu.buf->get_tailroom()) {
logger->error("%s Discarding SN=%d of size %d B (available space %d B)",
parent->rb_name,
header.sn,
nof_bytes,
rx_sdu.buf->get_tailroom());
return; return;
} }
memcpy(rx_sdu.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
rx_sdu.buf->N_bytes = nof_bytes - hdr_len;
rx_sdu.fully_received = true;
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
} else { } else {
// Check if all bytes of the RLC SDU with SN = x are received: int err = handle_segment_data_sdu(header, payload, nof_bytes);
// TODO if (err != SRSRAN_SUCCESS) {
if (header.si == rlc_nr_si_field_t::first_segment) { // Check whether it's a full SDU return;
} else if (header.si == rlc_nr_si_field_t::last_segment) {
} else if (header.si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
} }
} }
// Check poll bit // Check poll bit
if (header.p) { if (header.p) {
logger->info("%s Status packet requested through polling bit", parent->rb_name); RlcInfo("status packet requested through polling bit");
do_status = true; do_status = true;
status_prohibit_timer.stop(); status_prohibit_timer.stop();
} }
@ -606,8 +749,8 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
if (st.rx_next_highest > st.rx_next + 1) { if (st.rx_next_highest > st.rx_next + 1) {
restart_reassembly_timer = true; restart_reassembly_timer = true;
} }
if (st.rx_next_highest == st.rx_next + 1 && if (st.rx_next_highest == st.rx_next + 1 && rx_window.has_sn(st.rx_next + 1) &&
rx_window[st.rx_next + 1].fully_received == false) { // TODO: does the last by need to be received? not rx_window[st.rx_next + 1].fully_received) {
restart_reassembly_timer = true; restart_reassembly_timer = true;
} }
if (restart_reassembly_timer) { if (restart_reassembly_timer) {
@ -617,6 +760,91 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
} }
} }
/*
* SDU handling helpers
*/
int rlc_am_nr_rx::handle_full_data_sdu(const rlc_am_nr_pdu_header_t& header, const uint8_t* payload, uint32_t nof_bytes)
{
uint32_t hdr_len = rlc_am_nr_packed_length(header);
// Full SDU received. Add SDU to Rx Window and copy full PDU into SDU buffer.
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.add_pdu(header.sn);
rx_sdu.buf = srsran::make_byte_buffer();
if (rx_sdu.buf == nullptr) {
RlcError("fatal error. Couldn't allocate PDU in %s.", __FUNCTION__);
rx_window.remove_pdu(header.sn);
return SRSRAN_ERROR;
}
rx_sdu.buf->set_timestamp();
// check available space for payload
if (nof_bytes > rx_sdu.buf->get_tailroom()) {
RlcError("discarding SN=%d of size %d B (available space %d B)", header.sn, nof_bytes, rx_sdu.buf->get_tailroom());
rx_window.remove_pdu(header.sn);
return SRSRAN_ERROR;
}
memcpy(rx_sdu.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
rx_sdu.buf->N_bytes = nof_bytes - hdr_len;
rx_sdu.fully_received = true;
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
return SRSRAN_SUCCESS;
}
int rlc_am_nr_rx::handle_segment_data_sdu(const rlc_am_nr_pdu_header_t& header,
const uint8_t* payload,
uint32_t nof_bytes)
{
if (header.si == rlc_nr_si_field_t::full_sdu) {
RlcError("called %s but the SI implies a full SDU. SN=%d", __FUNCTION__, header.sn);
return SRSRAN_ERROR;
}
uint32_t hdr_len = rlc_am_nr_packed_length(header);
// Log SDU segment reception
if (header.si == rlc_nr_si_field_t::first_segment) { // Check whether it's a full SDU
RlcDebug("Initial segment PDU. SN=%d.", header.sn);
} else if (header.si == rlc_nr_si_field_t::neither_first_nor_last_segment) {
RlcDebug("Middle segment PDU. SN=%d.", header.sn);
} else if (header.si == rlc_nr_si_field_t::last_segment) {
RlcDebug("Final segment PDU. SN=%d.", header.sn);
}
// Add a new SDU to the RX window if necessary
rlc_amd_rx_sdu_nr_t& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : rx_window.add_pdu(header.sn);
// Create PDU segment info, to be stored later
rlc_amd_rx_pdu_nr pdu_segment = {};
pdu_segment.header = header;
pdu_segment.buf = srsran::make_byte_buffer();
if (pdu_segment.buf == nullptr) {
RlcError("fatal error. Couldn't allocate PDU in %s.", __FUNCTION__);
return SRSRAN_ERROR;
}
memcpy(pdu_segment.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
pdu_segment.buf->N_bytes = nof_bytes - hdr_len;
// Store SDU segment. TODO sort by SO and check for duplicate bytes.
rx_sdu.segments.push_back(std::move(pdu_segment));
// Check weather all segments have been received
rx_sdu.fully_received = have_all_segments_been_received(rx_sdu.segments);
if (rx_sdu.fully_received) {
RlcInfo("Fully received segmented SDU. SN=%d.", header.sn);
rx_sdu.buf = srsran::make_byte_buffer();
if (rx_sdu.buf == nullptr) {
RlcError("fatal error. Couldn't allocate PDU in %s.", __FUNCTION__);
rx_window.remove_pdu(header.sn);
return SRSRAN_ERROR;
}
for (const auto& it : rx_sdu.segments) {
memcpy(&rx_sdu.buf->msg[rx_sdu.buf->N_bytes], it.buf->msg, it.buf->N_bytes);
rx_sdu.buf->N_bytes += it.buf->N_bytes;
}
write_to_upper_layers(parent->lcid, std::move(rx_window[header.sn].buf));
}
return SRSRAN_SUCCESS;
}
/* /*
* Status PDU * Status PDU
*/ */
@ -648,7 +876,7 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
} }
if (max_len != UINT32_MAX) { if (max_len != UINT32_MAX) {
// UINT32_MAX is used just to querry the status PDU length // UINT32_MAX is used just to query the status PDU length
if (status_prohibit_timer.is_valid()) { if (status_prohibit_timer.is_valid()) {
status_prohibit_timer.run(); status_prohibit_timer.run();
} }
@ -658,7 +886,7 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
uint32_t rlc_am_nr_rx::get_status_pdu_length() uint32_t rlc_am_nr_rx::get_status_pdu_length()
{ {
rlc_am_nr_status_pdu_t tmp_status; // length for no NACKs rlc_am_nr_status_pdu_t tmp_status;
return get_status_pdu(&tmp_status, UINT32_MAX); return get_status_pdu(&tmp_status, UINT32_MAX);
} }
@ -673,13 +901,13 @@ void rlc_am_nr_rx::timer_expired(uint32_t timeout_id)
// Status Prohibit // Status Prohibit
if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) {
logger->debug("%s Status prohibit timer expired after %dms", parent->rb_name, status_prohibit_timer.duration()); RlcDebug("Status prohibit timer expired after %dms", status_prohibit_timer.duration());
return; return;
} }
// Reassembly // Reassembly
if (reassembly_timer.is_valid() && reassembly_timer.id() == timeout_id) { if (reassembly_timer.is_valid() && reassembly_timer.id() == timeout_id) {
logger->debug("%s Reassembly timer expired after %dms", parent->rb_name, reassembly_timer.duration()); RlcDebug("Reassembly timer expired after %dms", reassembly_timer.duration());
/* /*
* 5.2.3.2.4 Actions when t-Reassembly expires: * 5.2.3.2.4 Actions when t-Reassembly expires:
* - update RX_Highest_Status to the SN of the first RLC SDU with SN >= RX_Next_Status_Trigger for which not * - update RX_Highest_Status to the SN of the first RLC SDU with SN >= RX_Next_Status_Trigger for which not
@ -755,15 +983,37 @@ uint32_t rlc_am_nr_rx::get_rx_buffered_bytes()
return 0; return 0;
} }
bool rlc_am_nr_rx::have_all_segments_been_received(const std::list<rlc_amd_rx_pdu_nr>& segment_list)
{
if (segment_list.empty()) {
return false;
}
// Check if we have received the last segment
if ((--segment_list.end())->header.si != rlc_nr_si_field_t::last_segment) {
return false;
}
// Check if all segments have been received
uint32_t next_byte = 0;
for (const auto& it : segment_list) {
if (it.header.so != next_byte) {
return false;
}
next_byte += it.buf->N_bytes;
}
return true;
}
/* /*
* Debug Helpers * Debug Helpers
*/ */
void rlc_am_nr_rx::debug_state() void rlc_am_nr_rx::debug_state()
{ {
logger->debug("RX entity state: Rx_Next %d, Rx_Next_Status_Trigger %d, Rx_Highest_Status %d, Rx_Next_Highest", RlcDebug("RX entity state: Rx_Next %d, Rx_Next_Status_Trigger %d, Rx_Highest_Status %d, Rx_Next_Highest",
st.rx_next, st.rx_next,
st.rx_next_status_trigger, st.rx_next_status_trigger,
st.rx_highest_status, st.rx_highest_status,
st.rx_next_highest); st.rx_next_highest);
} }
} // namespace srsran } // namespace srsran

@ -105,12 +105,9 @@ uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header)
return len; return len;
} }
uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu) uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, uint8_t* payload)
{ {
// Make room for the header uint8_t* ptr = payload;
uint32_t len = rlc_am_nr_packed_length(header);
pdu->msg -= len;
uint8_t* ptr = pdu->msg;
// fixed header part // fixed header part
*ptr = (header.dc & 0x01) << 7; ///< 1 bit D/C field *ptr = (header.dc & 0x01) << 7; ///< 1 bit D/C field
@ -140,9 +137,16 @@ uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, b
*ptr = (header.so & 0xff); // second part of SO *ptr = (header.so & 0xff); // second part of SO
ptr++; ptr++;
} }
return rlc_am_nr_packed_length(header);
}
pdu->N_bytes += ptr - pdu->msg; uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, byte_buffer_t* pdu)
{
// Make room for the header
uint32_t len = rlc_am_nr_packed_length(header);
pdu->msg -= len;
pdu->N_bytes += len;
rlc_am_nr_write_data_pdu_header(header, pdu->msg);
return len; return len;
} }

@ -30,9 +30,10 @@ rlc_tm::rlc_tm(srslog::basic_logger& logger,
uint32_t lcid_, uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_) : srsue::rrc_interface_rlc* rrc_) :
logger(logger), pdcp(pdcp_), rrc(rrc_), lcid(lcid_) rlc_common(logger), pdcp(pdcp_), rrc(rrc_), lcid(lcid_)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
rb_name = "SRB0";
} }
// Warning: must call stop() to properly deallocate all buffers // Warning: must call stop() to properly deallocate all buffers
@ -43,7 +44,7 @@ rlc_tm::~rlc_tm()
bool rlc_tm::configure(const rlc_config_t& cnfg) bool rlc_tm::configure(const rlc_config_t& cnfg)
{ {
logger.error("Attempted to configure TM RLC entity"); RlcError("Attempted to configure TM RLC entity");
return true; return true;
} }
@ -89,23 +90,17 @@ void rlc_tm::write_sdu(unique_byte_buffer_t sdu)
uint32_t nof_bytes = sdu->N_bytes; uint32_t nof_bytes = sdu->N_bytes;
srsran::error_type<unique_byte_buffer_t> ret = ul_queue.try_write(std::move(sdu)); srsran::error_type<unique_byte_buffer_t> ret = ul_queue.try_write(std::move(sdu));
if (ret) { if (ret) {
logger.info(msg_ptr, RlcHexInfo(msg_ptr, nof_bytes, "Tx SDU, queue size=%d, bytes=%d", ul_queue.size(), ul_queue.size_bytes());
nof_bytes,
"%s Tx SDU, queue size=%d, bytes=%d",
rrc->get_rb_name(lcid),
ul_queue.size(),
ul_queue.size_bytes());
} else { } else {
logger.warning(ret.error()->msg, RlcHexWarning(ret.error()->msg,
ret.error()->N_bytes, ret.error()->N_bytes,
"[Dropped SDU] %s Tx SDU, queue size=%d, bytes=%d", "[Dropped SDU] Tx SDU, queue size=%d, bytes=%d",
rrc->get_rb_name(lcid), ul_queue.size(),
ul_queue.size(), ul_queue.size_bytes());
ul_queue.size_bytes());
} }
} else { } else {
logger.warning("NULL SDU pointer in write_sdu()"); RlcWarning("NULL SDU pointer in write_sdu()");
} }
} }
@ -114,7 +109,7 @@ void rlc_tm::discard_sdu(uint32_t discard_sn)
if (!tx_enabled) { if (!tx_enabled) {
return; return;
} }
logger.warning("SDU discard not implemented on RLC TM"); RlcWarning("SDU discard not implemented on RLC TM");
} }
bool rlc_tm::sdu_queue_is_full() bool rlc_tm::sdu_queue_is_full()
@ -162,34 +157,31 @@ uint32_t rlc_tm::read_pdu(uint8_t* payload, uint32_t nof_bytes)
{ {
uint32_t pdu_size = ul_queue.size_tail_bytes(); uint32_t pdu_size = ul_queue.size_tail_bytes();
if (pdu_size > nof_bytes) { if (pdu_size > nof_bytes) {
logger.info("%s Tx PDU size larger than MAC opportunity (%d > %d)", rrc->get_rb_name(lcid), pdu_size, nof_bytes); RlcInfo("Tx PDU size larger than MAC opportunity (%d > %d)", pdu_size, nof_bytes);
return 0; return 0;
} }
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
if (ul_queue.try_read(&buf)) { if (ul_queue.try_read(&buf)) {
pdu_size = buf->N_bytes; pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes); memcpy(payload, buf->msg, buf->N_bytes);
logger.debug("%s Complete SDU scheduled for tx. Stack latency: %" PRIu64 " us", RlcDebug("Complete SDU scheduled for tx. Stack latency: %" PRIu64 " us", (uint64_t)buf->get_latency_us().count());
rrc->get_rb_name(lcid), RlcHexInfo(payload,
(uint64_t)buf->get_latency_us().count()); pdu_size,
logger.info(payload, "Tx %s PDU, queue size=%d, bytes=%d",
pdu_size, srsran::to_string(rlc_mode_t::tm),
"%s Tx %s PDU, queue size=%d, bytes=%d", ul_queue.size(),
rrc->get_rb_name(lcid), ul_queue.size_bytes());
srsran::to_string(rlc_mode_t::tm),
ul_queue.size(),
ul_queue.size_bytes());
std::lock_guard<std::mutex> lock(metrics_mutex); std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_tx_pdu_bytes += pdu_size; metrics.num_tx_pdu_bytes += pdu_size;
return pdu_size; return pdu_size;
} else {
if (ul_queue.size_bytes() > 0) {
logger.warning("Corrupted queue: empty but size_bytes > 0. Resetting queue");
ul_queue.reset();
}
return 0;
} }
if (ul_queue.size_bytes() > 0) {
RlcWarning("Corrupted queue: empty but size_bytes > 0. Resetting queue");
ul_queue.reset();
}
return 0;
} }
void rlc_tm::write_pdu(uint8_t* payload, uint32_t nof_bytes) void rlc_tm::write_pdu(uint8_t* payload, uint32_t nof_bytes)
@ -210,7 +202,7 @@ void rlc_tm::write_pdu(uint8_t* payload, uint32_t nof_bytes)
pdcp->write_pdu(lcid, std::move(buf)); pdcp->write_pdu(lcid, std::move(buf));
} }
} else { } else {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu().");
} }
} }

@ -30,7 +30,7 @@ rlc_um_base::rlc_um_base(srslog::basic_logger& logger,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_) : srsran::timer_handler* timers_) :
logger(logger), lcid(lcid_), pdcp(pdcp_), rrc(rrc_), timers(timers_), pool(byte_buffer_pool::get_instance()) rlc_common(logger), lcid(lcid_), pdcp(pdcp_), rrc(rrc_), timers(timers_), pool(byte_buffer_pool::get_instance())
{} {}
rlc_um_base::~rlc_um_base() {} rlc_um_base::~rlc_um_base() {}
@ -90,7 +90,7 @@ void rlc_um_base::empty_queue()
void rlc_um_base::write_sdu(unique_byte_buffer_t sdu) void rlc_um_base::write_sdu(unique_byte_buffer_t sdu)
{ {
if (not tx_enabled || not tx) { if (not tx_enabled || not tx) {
logger.debug("%s is currently deactivated. Dropping SDU (%d B)", rb_name.c_str(), sdu->N_bytes); RlcDebug("RB is currently deactivated. Dropping SDU (%d B)", sdu->N_bytes);
std::lock_guard<std::mutex> lock(metrics_mutex); std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_lost_sdus++; metrics.num_lost_sdus++;
return; return;
@ -110,7 +110,7 @@ void rlc_um_base::write_sdu(unique_byte_buffer_t sdu)
void rlc_um_base::discard_sdu(uint32_t discard_sn) void rlc_um_base::discard_sdu(uint32_t discard_sn)
{ {
if (not tx_enabled || not tx) { if (not tx_enabled || not tx) {
logger.debug("%s is currently deactivated. Ignoring SDU discard (SN=%u)", rb_name.c_str(), discard_sn); RlcDebug("RB is currently deactivated. Ignoring SDU discard (SN=%u)", discard_sn);
return; return;
} }
tx->discard_sdu(discard_sn); tx->discard_sdu(discard_sn);
@ -275,15 +275,10 @@ void rlc_um_base::rlc_um_base_tx::set_bsr_callback(bsr_callback_t callback)
void rlc_um_base::rlc_um_base_tx::write_sdu(unique_byte_buffer_t sdu) void rlc_um_base::rlc_um_base_tx::write_sdu(unique_byte_buffer_t sdu)
{ {
if (sdu) { if (sdu) {
logger.info(sdu->msg, RlcHexInfo(sdu->msg, sdu->N_bytes, "Tx SDU (%d B, tx_sdu_queue_len=%d)", sdu->N_bytes, tx_sdu_queue.size());
sdu->N_bytes,
"%s Tx SDU (%d B, tx_sdu_queue_len=%d)",
rb_name.c_str(),
sdu->N_bytes,
tx_sdu_queue.size());
tx_sdu_queue.write(std::move(sdu)); tx_sdu_queue.write(std::move(sdu));
} else { } else {
logger.warning("NULL SDU pointer in write_sdu()"); RlcWarning("NULL SDU pointer in write_sdu()");
} }
} }
@ -294,26 +289,25 @@ int rlc_um_base::rlc_um_base_tx::try_write_sdu(unique_byte_buffer_t sdu)
uint32_t nof_bytes = sdu->N_bytes; uint32_t nof_bytes = sdu->N_bytes;
srsran::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu)); srsran::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu));
if (ret) { if (ret) {
logger.info( RlcHexInfo(msg_ptr, nof_bytes, "Tx SDU (%d B, tx_sdu_queue_len=%d)", nof_bytes, tx_sdu_queue.size());
msg_ptr, nof_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rb_name.c_str(), nof_bytes, tx_sdu_queue.size());
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} else { } else {
logger.warning(ret.error()->msg, RlcHexWarning(ret.error()->msg,
ret.error()->N_bytes, ret.error()->N_bytes,
"[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)",
rb_name.c_str(), rb_name.c_str(),
ret.error()->N_bytes, ret.error()->N_bytes,
tx_sdu_queue.size()); tx_sdu_queue.size());
} }
} else { } else {
logger.warning("NULL SDU pointer in write_sdu()"); RlcWarning("NULL SDU pointer in write_sdu()");
} }
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
void rlc_um_base::rlc_um_base_tx::discard_sdu(uint32_t discard_sn) void rlc_um_base::rlc_um_base_tx::discard_sdu(uint32_t discard_sn)
{ {
logger.warning("RLC UM: Discard SDU not implemented yet."); RlcWarning("RLC UM: Discard SDU not implemented yet.");
} }
bool rlc_um_base::rlc_um_base_tx::sdu_queue_is_full() bool rlc_um_base::rlc_um_base_tx::sdu_queue_is_full()
@ -326,16 +320,16 @@ uint32_t rlc_um_base::rlc_um_base_tx::build_data_pdu(uint8_t* payload, uint32_t
unique_byte_buffer_t pdu; unique_byte_buffer_t pdu;
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
logger.debug("MAC opportunity - %d bytes", nof_bytes); RlcDebug("MAC opportunity - %d bytes", nof_bytes);
if (tx_sdu == nullptr && tx_sdu_queue.is_empty()) { if (tx_sdu == nullptr && tx_sdu_queue.is_empty()) {
logger.info("No data available to be sent"); RlcInfo("No data available to be sent");
return 0; return 0;
} }
pdu = make_byte_buffer(); pdu = make_byte_buffer();
if (!pdu || pdu->N_bytes != 0) { if (!pdu || pdu->N_bytes != 0) {
logger.error("Failed to allocate PDU buffer"); RlcError("Failed to allocate PDU buffer");
return 0; return 0;
} }
} }

@ -59,12 +59,11 @@ bool rlc_um_lte::configure(const rlc_config_t& cnfg_)
return false; return false;
} }
logger.info("%s configured in %s: t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits", RlcInfo("configured in %s - t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits",
rb_name.c_str(), srsran::to_string(cnfg_.rlc_mode),
srsran::to_string(cnfg_.rlc_mode), cfg.um.t_reordering,
cfg.um.t_reordering, srsran::to_number(cfg.um.rx_sn_field_length),
srsran::to_number(cfg.um.rx_sn_field_length), srsran::to_number(cfg.um.tx_sn_field_length));
srsran::to_number(cfg.um.tx_sn_field_length));
rx_enabled = true; rx_enabled = true;
tx_enabled = true; tx_enabled = true;
@ -111,7 +110,7 @@ bool rlc_um_lte::rlc_um_lte_tx::configure(const rlc_config_t& cnfg_, std::string
cfg = cnfg_; cfg = cnfg_;
if (cfg.um.tx_mod == 0) { if (cfg.um.tx_mod == 0) {
logger.error("Error configuring %s RLC UM: tx_mod==0", rb_name.c_str()); RlcError("Error configuring RLC UM - tx_mod==0");
return false; return false;
} }
@ -139,10 +138,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
int pdu_space = SRSRAN_MIN(nof_bytes, pdu->get_tailroom()); int pdu_space = SRSRAN_MIN(nof_bytes, pdu->get_tailroom());
if (pdu_space <= head_len + 1) { if (pdu_space <= head_len + 1) {
logger.info("%s Cannot build a PDU - %d bytes available, %d bytes required for header", RlcInfo("Cannot build a PDU - %d bytes available, %d bytes required for header", nof_bytes, head_len);
rb_name.c_str(),
nof_bytes,
head_len);
return 0; return 0;
} }
@ -150,8 +146,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
if (tx_sdu) { if (tx_sdu) {
uint32_t space = pdu_space - head_len; uint32_t space = pdu_space - head_len;
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
logger.debug( RlcDebug("adding remainder of SDU segment - %d bytes of %d remaining", to_move, tx_sdu->N_bytes);
"%s adding remainder of SDU segment - %d bytes of %d remaining", rb_name.c_str(), to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -162,12 +157,11 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
#ifdef ENABLE_TIMESTAMP #ifdef ENABLE_TIMESTAMP
auto latency_us = tx_sdu->get_latency_us().count(); auto latency_us = tx_sdu->get_latency_us().count();
mean_pdu_latency_us.push(latency_us); mean_pdu_latency_us.push(latency_us);
logger.debug("%s Complete SDU scheduled for tx. Stack latency (last/average): %" PRIu64 "/%ld us", RlcDebug("Complete SDU scheduled for tx. Stack latency (last/average): %" PRIu64 "/%ld us",
rb_name.c_str(), (uint64_t)latency_us,
(uint64_t)latency_us, (long)mean_pdu_latency_us.value());
(long)mean_pdu_latency_us.value());
#else #else
logger.debug("%s Complete SDU scheduled for tx.", rb_name.c_str()); RlcDebug("%s Complete SDU scheduled for tx.", rb_name.c_str());
#endif #endif
tx_sdu.reset(); tx_sdu.reset();
} }
@ -177,7 +171,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
// Pull SDUs from queue // Pull SDUs from queue
while (pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) { while (pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) {
logger.debug("pdu_space=%d, head_len=%d", pdu_space, head_len); RlcDebug("pdu_space=%d, head_len=%d", pdu_space, head_len);
if (last_li > 0) { if (last_li > 0) {
header.li[header.N_li++] = last_li; header.li[header.N_li++] = last_li;
} }
@ -190,7 +184,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
} }
tx_sdu = tx_sdu_queue.read(); tx_sdu = tx_sdu_queue.read();
to_move = (space >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : space; to_move = (space >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : space;
logger.debug("%s adding new SDU segment - %d bytes of %d remaining", rb_name.c_str(), to_move, tx_sdu->N_bytes); RlcDebug("adding new SDU segment - %d bytes of %d remaining", to_move, tx_sdu->N_bytes);
memcpy(pdu_ptr, tx_sdu->msg, to_move); memcpy(pdu_ptr, tx_sdu->msg, to_move);
last_li = to_move; last_li = to_move;
pdu_ptr += to_move; pdu_ptr += to_move;
@ -201,12 +195,11 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
#ifdef ENABLE_TIMESTAMP #ifdef ENABLE_TIMESTAMP
auto latency_us = tx_sdu->get_latency_us().count(); auto latency_us = tx_sdu->get_latency_us().count();
mean_pdu_latency_us.push(latency_us); mean_pdu_latency_us.push(latency_us);
logger.debug("%s Complete SDU scheduled for tx. Stack latency (last/average): %" PRIu64 "/%ld us", RlcDebug("Complete SDU scheduled for tx. Stack latency (last/average): %" PRIu64 "/%ld us",
rb_name.c_str(), (uint64_t)latency_us,
(uint64_t)latency_us, (long)mean_pdu_latency_us.value());
(long)mean_pdu_latency_us.value());
#else #else
logger.debug("%s Complete SDU scheduled for tx.", rb_name.c_str()); RlcDebug("Complete SDU scheduled for tx.");
#endif #endif
tx_sdu.reset(); tx_sdu.reset();
} }
@ -225,7 +218,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
rlc_um_write_data_pdu_header(&header, pdu.get()); rlc_um_write_data_pdu_header(&header, pdu.get());
memcpy(payload, pdu->msg, pdu->N_bytes); memcpy(payload, pdu->msg, pdu->N_bytes);
logger.info(payload, pdu->N_bytes, "%s Tx PDU SN=%d (%d B)", rb_name.c_str(), header.sn, pdu->N_bytes); RlcHexInfo(payload, pdu->N_bytes, "Tx PDU SN=%d (%d B)", header.sn, pdu->N_bytes);
debug_state(); debug_state();
@ -234,7 +227,7 @@ uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uin
void rlc_um_lte::rlc_um_lte_tx::debug_state() void rlc_um_lte::rlc_um_lte_tx::debug_state()
{ {
logger.debug("%s vt_us = %d", rb_name.c_str(), vt_us); RlcDebug("vt_us = %d", vt_us);
} }
void rlc_um_lte::rlc_um_lte_tx::reset() void rlc_um_lte::rlc_um_lte_tx::reset()
@ -256,14 +249,16 @@ bool rlc_um_lte::rlc_um_lte_rx::configure(const rlc_config_t& cnfg_, std::string
{ {
cfg = cnfg_; cfg = cnfg_;
rb_name = rb_name_;
if (cfg.um.rx_mod == 0) { if (cfg.um.rx_mod == 0) {
logger.error("Error configuring %s RLC UM: rx_mod==0", rb_name.c_str()); RlcError("Error configuring RLC UM: rx_mod==0");
return false; return false;
} }
// check timer // check timer
if (not reordering_timer.is_valid()) { if (not reordering_timer.is_valid()) {
logger.error("Configuring RLC UM RX: timers not configured"); RlcError("Configuring RLC UM RX: timers not configured");
return false; return false;
} }
@ -272,8 +267,6 @@ bool rlc_um_lte::rlc_um_lte_rx::configure(const rlc_config_t& cnfg_, std::string
reordering_timer.set(static_cast<uint32_t>(cfg.um.t_reordering), [this](uint32_t tid) { timer_expired(tid); }); reordering_timer.set(static_cast<uint32_t>(cfg.um.t_reordering), [this](uint32_t tid) { timer_expired(tid); });
} }
rb_name = rb_name_;
return true; return true;
} }
@ -312,17 +305,17 @@ void rlc_um_lte::rlc_um_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b
{ {
rlc_umd_pdu_header_t header; rlc_umd_pdu_header_t header;
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.um.rx_sn_field_length, &header); rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.um.rx_sn_field_length, &header);
logger.info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", rb_name.c_str(), header.sn, nof_bytes); RlcHexInfo(payload, nof_bytes, "Rx data PDU SN=%d (%d B)", header.sn, nof_bytes);
if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh - cfg.um.rx_window_size) && if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh - cfg.um.rx_window_size) &&
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) {
logger.info("%s SN=%d outside rx window [%d:%d] - discarding", rb_name.c_str(), header.sn, vr_ur, vr_uh); RlcInfo("SN=%d outside rx window [%d:%d] - discarding", header.sn, vr_ur, vr_uh);
return; return;
} }
std::map<uint32_t, rlc_umd_pdu_t>::iterator it = rx_window.find(header.sn); std::map<uint32_t, rlc_umd_pdu_t>::iterator it = rx_window.find(header.sn);
if (rx_window.end() != it) { if (rx_window.end() != it) {
logger.info("%s Discarding duplicate SN=%d", rb_name.c_str(), header.sn); RlcInfo("Discarding duplicate SN=%d", header.sn);
return; return;
} }
@ -330,7 +323,7 @@ void rlc_um_lte::rlc_um_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b
rlc_umd_pdu_t pdu = {}; rlc_umd_pdu_t pdu = {};
pdu.buf = make_byte_buffer(); pdu.buf = make_byte_buffer();
if (!pdu.buf) { if (!pdu.buf) {
logger.error("Discarting packet: no space in buffer pool"); RlcError("Discarding packet: no space in buffer pool");
return; return;
} }
memcpy(pdu.buf->msg, payload, nof_bytes); memcpy(pdu.buf->msg, payload, nof_bytes);
@ -348,9 +341,9 @@ void rlc_um_lte::rlc_um_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b
} }
// Reassemble and deliver SDUs, while updating vr_ur // Reassemble and deliver SDUs, while updating vr_ur
logger.debug("Entering Reassemble from received PDU"); RlcDebug("Entering Reassemble from received PDU");
reassemble_rx_sdus(); reassemble_rx_sdus();
logger.debug("Finished reassemble from received PDU"); RlcDebug("Finished reassemble from received PDU");
// Update reordering variables and timers // Update reordering variables and timers
if (reordering_timer.is_running()) { if (reordering_timer.is_running()) {
@ -374,32 +367,32 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
if (!rx_sdu) { if (!rx_sdu) {
rx_sdu = make_byte_buffer(); rx_sdu = make_byte_buffer();
if (!rx_sdu) { if (!rx_sdu) {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().");
return; return;
} }
} }
// First catch up with lower edge of reordering window // First catch up with lower edge of reordering window
while (!inside_reordering_window(vr_ur)) { while (!inside_reordering_window(vr_ur)) {
logger.debug("SN=%d is not inside reordering windows", vr_ur); RlcDebug("SN=%d is not inside reordering windows", vr_ur);
if (rx_window.end() == rx_window.find(vr_ur)) { if (rx_window.end() == rx_window.find(vr_ur)) {
logger.debug("SN=%d not in rx_window. Reset received SDU", vr_ur); RlcDebug("SN=%d not in rx_window. Reset received SDU", vr_ur);
rx_sdu->clear(); rx_sdu->clear();
} else { } else {
// Handle any SDU segments // Handle any SDU segments
for (uint32_t i = 0; i < rx_window[vr_ur].header.N_li; i++) { for (uint32_t i = 0; i < rx_window[vr_ur].header.N_li; i++) {
int len = rx_window[vr_ur].header.li[i]; int len = rx_window[vr_ur].header.li[i];
logger.debug(rx_window[vr_ur].buf->msg, RlcHexDebug(rx_window[vr_ur].buf->msg,
len, len,
"Handling segment %d/%d of length %d B of SN=%d", "Handling segment %d/%d of length %d B of SN=%d",
i + 1, i + 1,
rx_window[vr_ur].header.N_li, rx_window[vr_ur].header.N_li,
len, len,
vr_ur); vr_ur);
// Check if we received a middle or end segment // Check if we received a middle or end segment
if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.warning("Dropping PDU %d in reassembly due to lost start segment", vr_ur); RlcWarning("Dropping PDU %d in reassembly due to lost start segment", vr_ur);
// Advance data pointers and continue with next segment // Advance data pointers and continue with next segment
rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->msg += len;
rx_window[vr_ur].buf->N_bytes -= len; rx_window[vr_ur].buf->N_bytes -= len;
@ -414,18 +407,13 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
rx_window[vr_ur].buf->N_bytes -= len; rx_window[vr_ur].buf->N_bytes -= len;
if ((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) || if ((pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) ||
(vr_ur != ((vr_ur_in_rx_sdu + 1) % cfg.um.rx_mod))) { (vr_ur != ((vr_ur_in_rx_sdu + 1) % cfg.um.rx_mod))) {
logger.warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)", RlcWarning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)",
vr_ur, vr_ur,
vr_ur_in_rx_sdu); vr_ur_in_rx_sdu);
rx_sdu->clear(); rx_sdu->clear();
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
} else { } else {
logger.info(rx_sdu->msg, RlcHexInfo(rx_sdu->msg, rx_sdu->N_bytes, "Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", vr_ur, i);
rx_sdu->N_bytes,
"%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)",
rb_name.c_str(),
vr_ur,
i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
metrics.num_rx_sdus++; metrics.num_rx_sdus++;
metrics.num_rx_sdu_bytes += rx_sdu->N_bytes; metrics.num_rx_sdu_bytes += rx_sdu->N_bytes;
@ -436,7 +424,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
} }
rx_sdu = make_byte_buffer(); rx_sdu = make_byte_buffer();
if (!rx_sdu) { if (!rx_sdu) {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().");
return; return;
} }
} }
@ -445,22 +433,21 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
// Handle last segment // Handle last segment
if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.info("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d", RlcInfo("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d",
vr_ur, vr_ur,
rx_sdu->N_bytes, rx_sdu->N_bytes,
rx_window[vr_ur].buf->N_bytes); rx_window[vr_ur].buf->N_bytes);
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;
vr_ur_in_rx_sdu = vr_ur; vr_ur_in_rx_sdu = vr_ur;
if (rlc_um_end_aligned(rx_window[vr_ur].header.fi)) { if (rlc_um_end_aligned(rx_window[vr_ur].header.fi)) {
if (pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { if (pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.warning("Dropping remainder of lost PDU (lower edge last segments)"); RlcWarning("Dropping remainder of lost PDU (lower edge last segments)");
rx_sdu->clear(); rx_sdu->clear();
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
} else { } else {
logger.info( RlcHexInfo(rx_sdu->msg, rx_sdu->N_bytes, "Rx SDU vr_ur=%d (lower edge last segments)", vr_ur);
rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rb_name.c_str(), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
metrics.num_rx_sdus++; metrics.num_rx_sdus++;
metrics.num_rx_sdu_bytes += rx_sdu->N_bytes; metrics.num_rx_sdu_bytes += rx_sdu->N_bytes;
@ -471,7 +458,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
} }
rx_sdu = make_byte_buffer(); rx_sdu = make_byte_buffer();
if (!rx_sdu) { if (!rx_sdu) {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().");
return; return;
} }
} }
@ -488,10 +475,10 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
// Now update vr_ur until we reach an SN we haven't yet received // Now update vr_ur until we reach an SN we haven't yet received
while (rx_window.end() != rx_window.find(vr_ur)) { while (rx_window.end() != rx_window.find(vr_ur)) {
logger.debug("Reassemble loop for vr_ur=%d", vr_ur); RlcDebug("Reassemble loop for vr_ur=%d", vr_ur);
if (not pdu_belongs_to_rx_sdu()) { if (not pdu_belongs_to_rx_sdu()) {
logger.info("PDU SN=%d lost, stop reassambling SDU (vr_ur_in_rx_sdu=%d)", vr_ur_in_rx_sdu + 1, vr_ur_in_rx_sdu); RlcInfo("PDU SN=%d lost, stop reassambling SDU (vr_ur_in_rx_sdu=%d)", vr_ur_in_rx_sdu + 1, vr_ur_in_rx_sdu);
pdu_lost = false; // Reset flag to not prevent reassembling of further segments pdu_lost = false; // Reset flag to not prevent reassembling of further segments
rx_sdu->clear(); rx_sdu->clear();
} }
@ -499,22 +486,22 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
// Handle any SDU segments // Handle any SDU segments
for (uint32_t i = 0; i < rx_window[vr_ur].header.N_li; i++) { for (uint32_t i = 0; i < rx_window[vr_ur].header.N_li; i++) {
uint16_t len = rx_window[vr_ur].header.li[i]; uint16_t len = rx_window[vr_ur].header.li[i];
logger.debug("Handling SDU segment i=%d with len=%d of vr_ur=%d N_li=%d [%s]", RlcDebug("Handling SDU segment i=%d with len=%d of vr_ur=%d N_li=%d [%s]",
i, i,
len, len,
vr_ur, vr_ur,
rx_window[vr_ur].header.N_li, rx_window[vr_ur].header.N_li,
rlc_fi_field_text[rx_window[vr_ur].header.fi]); rlc_fi_field_text[rx_window[vr_ur].header.fi]);
// Check if the first part of the PDU is a middle or end segment // Check if the first part of the PDU is a middle or end segment
if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.info( RlcHexInfo(
rx_window[vr_ur].buf->msg, len, "Dropping first %d B of SN=%d due to lost start segment", len, vr_ur); rx_window[vr_ur].buf->msg, len, "Dropping first %d B of SN=%d due to lost start segment", len, vr_ur);
if (rx_window[vr_ur].buf->N_bytes < len) { if (rx_window[vr_ur].buf->N_bytes < len) {
logger.error("Dropping remaining remainder of SN=%d too (N_bytes=%u < len=%d)", RlcError("Dropping remaining remainder of SN=%d too (N_bytes=%u < len=%d)",
vr_ur, vr_ur,
rx_window[vr_ur].buf->N_bytes, rx_window[vr_ur].buf->N_bytes,
len); len);
goto clean_up_rx_window; goto clean_up_rx_window;
} }
@ -531,31 +518,31 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
// Check available space in SDU // Check available space in SDU
if ((uint32_t)len > rx_sdu->get_tailroom()) { if ((uint32_t)len > rx_sdu->get_tailroom()) {
logger.error("Dropping PDU %d due to buffer mis-alignment (current segment len %d B, received %d B)", RlcError("Dropping PDU %d due to buffer mis-alignment (current segment len %d B, received %d B)",
vr_ur, vr_ur,
rx_sdu->N_bytes, rx_sdu->N_bytes,
len); len);
rx_sdu->clear(); rx_sdu->clear();
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
goto clean_up_rx_window; goto clean_up_rx_window;
} }
if (not pdu_belongs_to_rx_sdu()) { if (not pdu_belongs_to_rx_sdu()) {
logger.info(rx_window[vr_ur].buf->msg, len, "Copying first %d bytes of new SDU", len); RlcHexInfo(rx_window[vr_ur].buf->msg, len, "Copying first %d bytes of new SDU", len);
logger.info("Updating vr_ur_in_rx_sdu. old=%d, new=%d", vr_ur_in_rx_sdu, vr_ur); RlcInfo("Updating vr_ur_in_rx_sdu. old=%d, new=%d", vr_ur_in_rx_sdu, vr_ur);
vr_ur_in_rx_sdu = vr_ur; vr_ur_in_rx_sdu = vr_ur;
} else { } else {
logger.info(rx_window[vr_ur].buf->msg, RlcHexInfo(rx_window[vr_ur].buf->msg,
len, len,
"Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, " "Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, "
"vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d", "vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d",
len, len,
rx_sdu->N_bytes, rx_sdu->N_bytes,
rx_window[vr_ur].buf->N_bytes, rx_window[vr_ur].buf->N_bytes,
vr_ur_in_rx_sdu, vr_ur_in_rx_sdu,
vr_ur, vr_ur,
cfg.um.rx_mod, cfg.um.rx_mod,
(vr_ur_in_rx_sdu + 1) % cfg.um.rx_mod); (vr_ur_in_rx_sdu + 1) % cfg.um.rx_mod);
} }
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len);
@ -565,12 +552,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
vr_ur_in_rx_sdu = vr_ur; vr_ur_in_rx_sdu = vr_ur;
if (pdu_belongs_to_rx_sdu()) { if (pdu_belongs_to_rx_sdu()) {
logger.info(rx_sdu->msg, RlcHexInfo(rx_sdu->msg, rx_sdu->N_bytes, "Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", vr_ur, i);
rx_sdu->N_bytes,
"%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)",
rb_name.c_str(),
vr_ur,
i);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
metrics.num_rx_sdus++; metrics.num_rx_sdus++;
metrics.num_rx_sdu_bytes += rx_sdu->N_bytes; metrics.num_rx_sdu_bytes += rx_sdu->N_bytes;
@ -581,13 +563,13 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
} }
rx_sdu = make_byte_buffer(); rx_sdu = make_byte_buffer();
if (!rx_sdu) { if (!rx_sdu) {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().");
return; return;
} }
} else { } else {
logger.warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)", RlcWarning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)",
vr_ur, vr_ur,
vr_ur_in_rx_sdu); vr_ur_in_rx_sdu);
// Advance data pointers and continue with next segment // Advance data pointers and continue with next segment
rx_window[vr_ur].buf->msg += len; rx_window[vr_ur].buf->msg += len;
rx_window[vr_ur].buf->N_bytes -= len; rx_window[vr_ur].buf->N_bytes -= len;
@ -599,7 +581,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
// Handle last segment // Handle last segment
if (rx_sdu->N_bytes == 0 && rx_window[vr_ur].header.N_li == 0 && if (rx_sdu->N_bytes == 0 && rx_window[vr_ur].header.N_li == 0 &&
!rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.warning("Dropping PDU %d during last segment handling due to lost start segment", vr_ur); RlcWarning("Dropping PDU %d during last segment handling due to lost start segment", vr_ur);
rx_sdu->clear(); rx_sdu->clear();
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
goto clean_up_rx_window; goto clean_up_rx_window;
@ -608,31 +590,30 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
if (rx_sdu->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES && if (rx_sdu->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES &&
rx_window[vr_ur].buf->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES && rx_window[vr_ur].buf->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES &&
rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES) { rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSRAN_MAX_BUFFER_SIZE_BYTES) {
logger.info(rx_window[vr_ur].buf->msg, RlcHexInfo(rx_window[vr_ur].buf->msg,
rx_window[vr_ur].buf->N_bytes, rx_window[vr_ur].buf->N_bytes,
"Writing last segment in SDU buffer. Updating vr_ur=%d, vr_ur_in_rx_sdu=%d, Buffer size=%d, " "Writing last segment in SDU buffer. Updating vr_ur=%d, vr_ur_in_rx_sdu=%d, Buffer size=%d, "
"segment size=%d", "segment size=%d",
vr_ur, vr_ur,
vr_ur_in_rx_sdu, vr_ur_in_rx_sdu,
rx_sdu->N_bytes, rx_sdu->N_bytes,
rx_window[vr_ur].buf->N_bytes); rx_window[vr_ur].buf->N_bytes);
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;
} else { } else {
logger.error("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d", RlcError("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d",
rx_sdu->N_bytes, rx_sdu->N_bytes,
rx_window[vr_ur].buf->N_bytes, rx_window[vr_ur].buf->N_bytes,
vr_ur); vr_ur);
} }
vr_ur_in_rx_sdu = vr_ur; vr_ur_in_rx_sdu = vr_ur;
if (rlc_um_end_aligned(rx_window[vr_ur].header.fi)) { if (rlc_um_end_aligned(rx_window[vr_ur].header.fi)) {
if (pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { if (pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) {
logger.warning("Dropping remainder of lost PDU (update vr_ur last segments)"); RlcWarning("Dropping remainder of lost PDU (update vr_ur last segments)");
rx_sdu->clear(); rx_sdu->clear();
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
} else { } else {
logger.info( RlcHexInfo(rx_sdu->msg, rx_sdu->N_bytes, "Rx SDU vr_ur=%d (update vr_ur last segments)", vr_ur);
rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name.c_str(), vr_ur);
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
metrics.num_rx_sdus++; metrics.num_rx_sdus++;
metrics.num_rx_sdu_bytes += rx_sdu->N_bytes; metrics.num_rx_sdu_bytes += rx_sdu->N_bytes;
@ -643,7 +624,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus()
} }
rx_sdu = make_byte_buffer(); rx_sdu = make_byte_buffer();
if (!rx_sdu) { if (!rx_sdu) {
logger.error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus()."); RlcError("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().");
return; return;
} }
} }
@ -690,9 +671,9 @@ void rlc_um_lte::rlc_um_lte_rx::timer_expired(uint32_t timeout_id)
{ {
if (reordering_timer.id() == timeout_id) { if (reordering_timer.id() == timeout_id) {
// 36.322 v10 Section 5.1.2.2.4 // 36.322 v10 Section 5.1.2.2.4
logger.info("%s reordering timeout expiry - updating vr_ur and reassembling", rb_name.c_str()); RlcInfo("%s reordering timeout expiry - updating vr_ur and reassembling", rb_name.c_str());
logger.warning("Lost PDU SN=%d", vr_ur); RlcWarning("Lost PDU SN=%d", vr_ur);
pdu_lost = true; pdu_lost = true;
if (rx_sdu != NULL) { if (rx_sdu != NULL) {
@ -701,9 +682,9 @@ void rlc_um_lte::rlc_um_lte_rx::timer_expired(uint32_t timeout_id)
while (RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) { while (RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) {
vr_ur = (vr_ur + 1) % cfg.um.rx_mod; vr_ur = (vr_ur + 1) % cfg.um.rx_mod;
logger.debug("Entering Reassemble from timeout id=%d", timeout_id); RlcDebug("Entering Reassemble from timeout id=%d", timeout_id);
reassemble_rx_sdus(); reassemble_rx_sdus();
logger.debug("Finished reassemble from timeout id=%d", timeout_id); RlcDebug("Finished reassemble from timeout id=%d", timeout_id);
} }
if (RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { if (RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) {
@ -721,7 +702,7 @@ void rlc_um_lte::rlc_um_lte_rx::timer_expired(uint32_t timeout_id)
void rlc_um_lte::rlc_um_lte_rx::debug_state() void rlc_um_lte::rlc_um_lte_rx::debug_state()
{ {
logger.debug("%s vr_ur = %d, vr_ux = %d, vr_uh = %d", rb_name.c_str(), vr_ur, vr_ux, vr_uh); RlcDebug("vr_ur = %d, vr_ux = %d, vr_uh = %d", vr_ur, vr_ux, vr_uh);
} }
/**************************************************************************** /****************************************************************************

@ -58,11 +58,10 @@ bool rlc_um_nr::configure(const rlc_config_t& cnfg_)
return false; return false;
} }
logger.info("%s configured in %s: sn_field_length=%u bits, t_reassembly=%d ms", RlcInfo("configured in %s: sn_field_length=%u bits, t_reassembly=%d ms",
rb_name.c_str(), srsran::to_string(cnfg_.rlc_mode),
srsran::to_string(cnfg_.rlc_mode), srsran::to_number(cfg.um_nr.sn_field_length),
srsran::to_number(cfg.um_nr.sn_field_length), cfg.um_nr.t_reassembly_ms);
cfg.um_nr.t_reassembly_ms);
rx_enabled = true; rx_enabled = true;
tx_enabled = true; tx_enabled = true;
@ -142,7 +141,7 @@ uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8
{ {
// Sanity check (we need at least 2B for a SDU) // Sanity check (we need at least 2B for a SDU)
if (nof_bytes < 2) { if (nof_bytes < 2) {
logger.warning("%s Cannot build a PDU with %d byte.", rb_name.c_str(), nof_bytes); RlcWarning("Cannot build a PDU with %d byte.", nof_bytes);
return 0; return 0;
} }
@ -179,10 +178,7 @@ uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8
// Calculate actual header length // Calculate actual header length
uint32_t head_len = rlc_um_nr_packed_length(header); uint32_t head_len = rlc_um_nr_packed_length(header);
if (pdu_space <= head_len + 1) { if (pdu_space <= head_len + 1) {
logger.info("%s Cannot build a PDU - %d bytes available, %d bytes required for header", RlcInfo("Cannot build a PDU - %d bytes available, %d bytes required for header", nof_bytes, head_len);
rb_name.c_str(),
nof_bytes,
head_len);
return 0; return 0;
} }
@ -191,7 +187,7 @@ uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8
uint32_t to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; uint32_t to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
// Log // Log
logger.debug("%s adding %s - (%d/%d)", rb_name.c_str(), to_string(header.si).c_str(), to_move, tx_sdu->N_bytes); RlcDebug("adding %s - (%d/%d)", to_string(header.si).c_str(), to_move, tx_sdu->N_bytes);
// Move data from SDU to PDU // Move data from SDU to PDU
uint8_t* pdu_ptr = pdu->msg; uint8_t* pdu_ptr = pdu->msg;
@ -226,9 +222,9 @@ uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8
if (header.si == rlc_nr_si_field_t::full_sdu) { if (header.si == rlc_nr_si_field_t::full_sdu) {
// log without SN // log without SN
logger.info(payload, ret, "%s Tx PDU (%d B)", rb_name.c_str(), pdu->N_bytes); RlcHexInfo(payload, ret, "Tx PDU (%d B)", pdu->N_bytes);
} else { } else {
logger.info(payload, ret, "%s Tx PDU SN=%d (%d B)", rb_name.c_str(), header.sn, pdu->N_bytes); RlcHexInfo(payload, ret, "Tx PDU SN=%d (%d B)", header.sn, pdu->N_bytes);
} }
debug_state(); debug_state();
@ -238,7 +234,7 @@ uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8
void rlc_um_nr::rlc_um_nr_tx::debug_state() void rlc_um_nr::rlc_um_nr_tx::debug_state()
{ {
logger.debug("%s TX_Next=%d, next_so=%d", rb_name.c_str(), TX_Next, next_so); RlcDebug("TX_Next=%d, next_so=%d", TX_Next, next_so);
} }
void rlc_um_nr::rlc_um_nr_tx::reset() void rlc_um_nr::rlc_um_nr_tx::reset()
@ -260,9 +256,11 @@ bool rlc_um_nr::rlc_um_nr_rx::configure(const rlc_config_t& cnfg_, std::string r
mod = (cfg.um_nr.sn_field_length == rlc_um_nr_sn_size_t::size6bits) ? 64 : 4096; mod = (cfg.um_nr.sn_field_length == rlc_um_nr_sn_size_t::size6bits) ? 64 : 4096;
UM_Window_Size = (cfg.um_nr.sn_field_length == rlc_um_nr_sn_size_t::size6bits) ? 32 : 2048; UM_Window_Size = (cfg.um_nr.sn_field_length == rlc_um_nr_sn_size_t::size6bits) ? 32 : 2048;
rb_name = rb_name_;
// check timer // check timer
if (not reassembly_timer.is_valid()) { if (not reassembly_timer.is_valid()) {
logger.error("Configuring RLC UM NR RX: timers not configured"); RlcError("Configuring RLC UM NR RX: timers not configured");
return false; return false;
} }
@ -272,8 +270,6 @@ bool rlc_um_nr::rlc_um_nr_rx::configure(const rlc_config_t& cnfg_, std::string r
[this](uint32_t tid) { timer_expired(tid); }); [this](uint32_t tid) { timer_expired(tid); });
} }
rb_name = rb_name_;
return true; return true;
} }
@ -313,9 +309,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
if (reassembly_timer.id() == timeout_id) { if (reassembly_timer.id() == timeout_id) {
logger.debug("%s reassembly timeout expiry for SN=%d - updating RX_Next_Reassembly and reassembling", RlcDebug("reassembly timeout expiry for SN=%d - updating RX_Next_Reassembly and reassembling", RX_Next_Reassembly);
rb_name.c_str(),
RX_Next_Reassembly);
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
@ -343,7 +337,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
if (RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1) || if (RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1) ||
((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) && ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) &&
has_missing_byte_segment(RX_Next_Reassembly)))) { has_missing_byte_segment(RX_Next_Reassembly)))) {
logger.debug("%s starting reassembly timer for SN=%d", rb_name.c_str(), RX_Next_Reassembly); RlcDebug("starting reassembly timer for SN=%d", rb_name.c_str(), RX_Next_Reassembly);
reassembly_timer.run(); reassembly_timer.run();
RX_Timer_Trigger = RX_Next_Highest; RX_Timer_Trigger = RX_Next_Highest;
} }
@ -372,7 +366,7 @@ unique_byte_buffer_t rlc_um_nr::rlc_um_nr_rx::rlc_um_nr_strip_pdu_header(const r
{ {
unique_byte_buffer_t sdu = make_byte_buffer(); unique_byte_buffer_t sdu = make_byte_buffer();
if (sdu == nullptr) { if (sdu == nullptr) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); RlcError("Couldn't allocate PDU in %s().", __FUNCTION__);
return nullptr; return nullptr;
} }
memcpy(sdu->msg, payload, nof_bytes); memcpy(sdu->msg, payload, nof_bytes);
@ -401,32 +395,32 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
// iterate over received segments and try to assemble full SDU // iterate over received segments and try to assemble full SDU
auto& pdu = rx_window.at(sn); auto& pdu = rx_window.at(sn);
for (auto it = pdu.segments.begin(); it != pdu.segments.end();) { for (auto it = pdu.segments.begin(); it != pdu.segments.end();) {
logger.debug("Have %s segment with SO=%d for SN=%d", RlcDebug("Have %s segment with SO=%d for SN=%d",
to_string_short(it->second.header.si).c_str(), to_string_short(it->second.header.si).c_str(),
it->second.header.so, it->second.header.so,
it->second.header.sn); it->second.header.sn);
if (it->second.header.so == pdu.next_expected_so) { if (it->second.header.so == pdu.next_expected_so) {
if (pdu.next_expected_so == 0) { if (pdu.next_expected_so == 0) {
if (pdu.sdu == nullptr) { if (pdu.sdu == nullptr) {
// reuse buffer of first segment for final SDU // reuse buffer of first segment for final SDU
pdu.sdu = std::move(it->second.buf); pdu.sdu = std::move(it->second.buf);
pdu.next_expected_so = pdu.sdu->N_bytes; pdu.next_expected_so = pdu.sdu->N_bytes;
logger.debug("Reusing first segment of SN=%d for final SDU", it->second.header.sn); RlcDebug("Reusing first segment of SN=%d for final SDU", it->second.header.sn);
it = pdu.segments.erase(it); it = pdu.segments.erase(it);
} else { } else {
logger.debug("SDU buffer already allocated. Possible retransmission of first segment."); RlcDebug("SDU buffer already allocated. Possible retransmission of first segment.");
if (it->second.header.so != pdu.next_expected_so) { if (it->second.header.so != pdu.next_expected_so) {
logger.error("Invalid PDU. SO doesn't match. Discarting all segments of SN=%d.", sn); RlcError("Invalid PDU. SO doesn't match. Discarding all segments of SN=%d.", sn);
rx_window.erase(sn); rx_window.erase(sn);
return; return;
} }
} }
} else { } else {
if (it->second.buf->N_bytes > pdu.sdu->get_tailroom()) { if (it->second.buf->N_bytes > pdu.sdu->get_tailroom()) {
logger.error("Cannot fit RLC PDU in SDU buffer (tailroom=%d, len=%d), dropping both. Erasing SN=%d.", RlcError("Cannot fit RLC PDU in SDU buffer (tailroom=%d, len=%d), dropping both. Erasing SN=%d.",
rx_sdu->get_tailroom(), rx_sdu->get_tailroom(),
it->second.buf->N_bytes, it->second.buf->N_bytes,
it->second.header.sn); it->second.header.sn);
rx_window.erase(sn); rx_window.erase(sn);
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
return; return;
@ -436,7 +430,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
memcpy(pdu.sdu->msg + pdu.sdu->N_bytes, it->second.buf->msg, it->second.buf->N_bytes); memcpy(pdu.sdu->msg + pdu.sdu->N_bytes, it->second.buf->msg, it->second.buf->N_bytes);
pdu.sdu->N_bytes += it->second.buf->N_bytes; pdu.sdu->N_bytes += it->second.buf->N_bytes;
pdu.next_expected_so += it->second.buf->N_bytes; pdu.next_expected_so += it->second.buf->N_bytes;
logger.debug("Appended SO=%d of SN=%d", it->second.header.so, it->second.header.sn); RlcDebug("Appended SO=%d of SN=%d", it->second.header.so, it->second.header.sn);
it = pdu.segments.erase(it); it = pdu.segments.erase(it);
if (pdu.next_expected_so == pdu.total_sdu_length) { if (pdu.next_expected_so == pdu.total_sdu_length) {
@ -453,7 +447,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
if (sdu_complete) { if (sdu_complete) {
// deliver full SDU to upper layers // deliver full SDU to upper layers
logger.info("%s Rx SDU (%d B)", rb_name.c_str(), pdu.sdu->N_bytes); RlcInfo("Rx SDU (%d B)", pdu.sdu->N_bytes);
pdcp->write_pdu(lcid, std::move(pdu.sdu)); pdcp->write_pdu(lcid, std::move(pdu.sdu));
// delete PDU from rx_window // delete PDU from rx_window
@ -466,29 +460,28 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
RX_Next_Reassembly = RX_Next_Highest; RX_Next_Reassembly = RX_Next_Highest;
} else { } else {
for (auto it = rx_window.begin(); it != rx_window.end(); ++it) { for (auto it = rx_window.begin(); it != rx_window.end(); ++it) {
logger.debug("SN=%d has %zd segments", it->first, it->second.segments.size()); RlcDebug("SN=%d has %zd segments", it->first, it->second.segments.size());
if (RX_MOD_NR_BASE(it->first) > RX_MOD_NR_BASE(RX_Next_Reassembly)) { if (RX_MOD_NR_BASE(it->first) > RX_MOD_NR_BASE(RX_Next_Reassembly)) {
RX_Next_Reassembly = it->first; RX_Next_Reassembly = it->first;
break; break;
} }
} }
} }
logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly); RlcDebug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly);
} }
} else if (not sn_in_reassembly_window(sn)) { } else if (not sn_in_reassembly_window(sn)) {
// SN outside of rx window // SN outside of rx window
RX_Next_Highest = (sn + 1) % mod; // update RX_Next_highest RX_Next_Highest = (sn + 1) % mod; // update RX_Next_highest
logger.debug("Updating RX_Next_Highest=%d", RX_Next_Highest); RlcDebug("Updating RX_Next_Highest=%d", RX_Next_Highest);
// drop all SNs outside of new rx window // drop all SNs outside of new rx window
for (auto it = rx_window.begin(); it != rx_window.end();) { for (auto it = rx_window.begin(); it != rx_window.end();) {
if (not sn_in_reassembly_window(it->first)) { if (not sn_in_reassembly_window(it->first)) {
logger.info("%s SN: %d outside rx window [%d:%d] - discarding", RlcInfo("SN=%d outside rx window [%d:%d] - discarding",
rb_name.c_str(), it->first,
it->first, RX_Next_Highest - UM_Window_Size,
RX_Next_Highest - UM_Window_Size, RX_Next_Highest);
RX_Next_Highest);
it = rx_window.erase(it); it = rx_window.erase(it);
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
} else { } else {
@ -501,7 +494,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
for (const auto& rx_pdu : rx_window) { for (const auto& rx_pdu : rx_window) {
if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) { if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) {
RX_Next_Reassembly = rx_pdu.first; RX_Next_Reassembly = rx_pdu.first;
logger.debug("%s Updating RX_Next_Reassembly=%d", rb_name.c_str(), RX_Next_Reassembly); RlcDebug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly);
break; break;
} }
} }
@ -512,7 +505,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
if (RX_Timer_Trigger <= RX_Next_Reassembly || if (RX_Timer_Trigger <= RX_Next_Reassembly ||
(not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) || (not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) ||
((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(RX_Next_Reassembly))) { ((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(RX_Next_Reassembly))) {
logger.debug("%s stopping reassembly timer", rb_name.c_str()); RlcDebug("stopping reassembly timer");
reassembly_timer.stop(); reassembly_timer.stop();
} }
} }
@ -521,13 +514,13 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
if ((RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) || if ((RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) ||
((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) && ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) &&
has_missing_byte_segment(RX_Next_Reassembly))) { has_missing_byte_segment(RX_Next_Reassembly))) {
logger.debug("%s Starting reassembly timer for SN=%d", rb_name.c_str(), sn); RlcDebug("Starting reassembly timer for SN=%d", sn);
reassembly_timer.run(); reassembly_timer.run();
RX_Timer_Trigger = RX_Next_Highest; RX_Timer_Trigger = RX_Next_Highest;
} }
} }
} else { } else {
logger.error("%s SN=%d does not exist in Rx buffer", rb_name.c_str(), sn); RlcError("SN=%d does not exist in Rx buffer", sn);
} }
} }
@ -536,10 +529,7 @@ inline void rlc_um_nr::rlc_um_nr_rx::update_total_sdu_length(rlc_umd_pdu_segment
{ {
if (rx_pdu.header.si == rlc_nr_si_field_t::last_segment) { if (rx_pdu.header.si == rlc_nr_si_field_t::last_segment) {
pdu_segments.total_sdu_length = rx_pdu.header.so + rx_pdu.buf->N_bytes; pdu_segments.total_sdu_length = rx_pdu.header.so + rx_pdu.buf->N_bytes;
logger.debug("%s updating total SDU length for SN=%d to %d B", RlcDebug("updating total SDU length for SN=%d to %d B", rx_pdu.header.sn, pdu_segments.total_sdu_length);
rb_name.c_str(),
rx_pdu.header.sn,
pdu_segments.total_sdu_length);
} }
}; };
@ -550,7 +540,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
rlc_um_nr_pdu_header_t header = {}; rlc_um_nr_pdu_header_t header = {};
rlc_um_nr_read_data_pdu_header(payload, nof_bytes, cfg.um_nr.sn_field_length, &header); rlc_um_nr_read_data_pdu_header(payload, nof_bytes, cfg.um_nr.sn_field_length, &header);
logger.debug(payload, nof_bytes, "%s Rx data PDU (%d B)", rb_name.c_str(), nof_bytes); RlcHexDebug(payload, nof_bytes, "Rx data PDU (%d B)", nof_bytes);
// check if PDU contains a SN // check if PDU contains a SN
if (header.si == rlc_nr_si_field_t::full_sdu) { if (header.si == rlc_nr_si_field_t::full_sdu) {
@ -558,10 +548,10 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
unique_byte_buffer_t sdu = rlc_um_nr_strip_pdu_header(header, payload, nof_bytes); unique_byte_buffer_t sdu = rlc_um_nr_strip_pdu_header(header, payload, nof_bytes);
// deliver to PDCP // deliver to PDCP
logger.info("%s Rx SDU (%d B)", rb_name.c_str(), sdu->N_bytes); RlcInfo("Rx SDU (%d B)", sdu->N_bytes);
pdcp->write_pdu(lcid, std::move(sdu)); pdcp->write_pdu(lcid, std::move(sdu));
} else if (sn_invalid_for_rx_buffer(header.sn)) { } else if (sn_invalid_for_rx_buffer(header.sn)) {
logger.info("%s Discarding SN=%d", rb_name.c_str(), header.sn); RlcInfo("Discarding SN=%d", header.sn);
// Nothing else to do here .. // Nothing else to do here ..
} else { } else {
// place PDU in receive buffer // place PDU in receive buffer
@ -572,26 +562,24 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
// check if this SN is already present in rx buffer // check if this SN is already present in rx buffer
if (rx_window.find(header.sn) == rx_window.end()) { if (rx_window.find(header.sn) == rx_window.end()) {
// first received segment of this SN, add to rx buffer // first received segment of this SN, add to rx buffer
logger.debug(rx_pdu.buf->msg, RlcHexDebug(rx_pdu.buf->msg,
rx_pdu.buf->N_bytes, rx_pdu.buf->N_bytes,
"%s placing %s segment of SN=%d (%d B) in Rx buffer", "placing %s segment of SN=%d (%d B) in Rx buffer",
rb_name.c_str(), to_string_short(header.si).c_str(),
to_string_short(header.si).c_str(), header.sn,
header.sn, rx_pdu.buf->N_bytes);
rx_pdu.buf->N_bytes);
rlc_umd_pdu_segments_nr_t pdu_segments = {}; rlc_umd_pdu_segments_nr_t pdu_segments = {};
update_total_sdu_length(pdu_segments, rx_pdu); update_total_sdu_length(pdu_segments, rx_pdu);
pdu_segments.segments.emplace(header.so, std::move(rx_pdu)); pdu_segments.segments.emplace(header.so, std::move(rx_pdu));
rx_window[header.sn] = std::move(pdu_segments); rx_window[header.sn] = std::move(pdu_segments);
} else { } else {
// other segment for this SN already present, update received data // other segment for this SN already present, update received data
logger.debug(rx_pdu.buf->msg, RlcHexDebug(rx_pdu.buf->msg,
rx_pdu.buf->N_bytes, rx_pdu.buf->N_bytes,
"%s updating SN=%d at SO=%d with %d B", "updating SN=%d at SO=%d with %d B",
rb_name.c_str(), rx_pdu.header.sn,
rx_pdu.header.sn, rx_pdu.header.so,
rx_pdu.header.so, rx_pdu.buf->N_bytes);
rx_pdu.buf->N_bytes);
auto& pdu_segments = rx_window.at(header.sn); auto& pdu_segments = rx_window.at(header.sn);
@ -611,12 +599,11 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
void rlc_um_nr::rlc_um_nr_rx::debug_state() void rlc_um_nr::rlc_um_nr_rx::debug_state()
{ {
logger.debug("%s RX_Next_Reassembly=%d, RX_Timer_Trigger=%d, RX_Next_Highest=%d, t_Reassembly=%s", RlcDebug("RX_Next_Reassembly=%d, RX_Timer_Trigger=%d, RX_Next_Highest=%d, t_Reassembly=%s",
rb_name.c_str(), RX_Next_Reassembly,
RX_Next_Reassembly, RX_Timer_Trigger,
RX_Timer_Trigger, RX_Next_Highest,
RX_Next_Highest, reassembly_timer.is_running() ? "running" : "stopped");
reassembly_timer.is_running() ? "running" : "stopped");
} }
/**************************************************************************** /****************************************************************************
* Header pack/unpack helper functions * Header pack/unpack helper functions

@ -653,6 +653,21 @@ int test_big_integers()
return 0; return 0;
} }
void test_varlength_field_pack()
{
uint8_t buffer[128];
bit_ref bref(&buffer[0], sizeof(buffer));
TESTASSERT_EQ(SRSRAN_SUCCESS, bref.pack(0, 1));
TESTASSERT_EQ(1, bref.distance());
{
varlength_field_pack_guard guard(bref);
TESTASSERT_EQ(0, bref.distance());
bref.pack(0, 8);
TESTASSERT_EQ(1, bref.distance_bytes());
}
TESTASSERT_EQ(17, bref.distance()); // accounts for length determinant and 1 byte of data
}
int main() int main()
{ {
// Setup the log spy to intercept error and warning log entries. // Setup the log spy to intercept error and warning log entries.
@ -681,6 +696,7 @@ int main()
TESTASSERT(test_copy_ptr() == 0); TESTASSERT(test_copy_ptr() == 0);
TESTASSERT(test_enum() == 0); TESTASSERT(test_enum() == 0);
TESTASSERT(test_big_integers() == 0); TESTASSERT(test_big_integers() == 0);
test_varlength_field_pack();
// TESTASSERT(test_json_writer()==0); // TESTASSERT(test_json_writer()==0);
srslog::flush(); srslog::flush();

@ -29,33 +29,33 @@ using namespace asn1::ngap;
int test_amf_upd() int test_amf_upd()
{ {
uint8_t ngap_msg[] = {0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x11}; uint8_t ngap_msg[] = {
0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x02, 0x80, 0x73, 0x72, 0x73, 0x72, 0x61, 0x6e};
cbit_ref bref(&ngap_msg[0], sizeof(ngap_msg)); cbit_ref bref(&ngap_msg[0], sizeof(ngap_msg));
// 0000000A00000100010003000011 // 0000000F00000100010008028073727372616E
ngap_pdu_c pdu; ngap_pdu_c pdu;
TESTASSERT(pdu.unpack(bref) == SRSASN_SUCCESS); TESTASSERT_EQ(SRSASN_SUCCESS, pdu.unpack(bref));
TESTASSERT(pdu.type().value == ngap_pdu_c::types_opts::init_msg); TESTASSERT_EQ(ngap_pdu_c::types_opts::init_msg, pdu.type().value);
TESTASSERT(pdu.init_msg().proc_code == 0); TESTASSERT_EQ(0, pdu.init_msg().proc_code);
TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject); TESTASSERT_EQ(crit_opts::reject, pdu.init_msg().crit.value);
ngap_elem_procs_o::init_msg_c& init_choice = pdu.init_msg().value; ngap_elem_procs_o::init_msg_c& init_choice = pdu.init_msg().value;
TESTASSERT(init_choice.type().value == ngap_elem_procs_o::init_msg_c::types_opts::amf_cfg_upd); TESTASSERT_EQ(ngap_elem_procs_o::init_msg_c::types_opts::amf_cfg_upd, init_choice.type().value);
amf_cfg_upd_s& amf_upd = init_choice.amf_cfg_upd(); amf_cfg_upd_s& amf_upd = init_choice.amf_cfg_upd();
TESTASSERT(not amf_upd.ext); TESTASSERT(not amf_upd.ext);
auto& amf_name = amf_upd.protocol_ies.amf_name; auto& amf_name = amf_upd->amf_name;
TESTASSERT(amf_upd.protocol_ies.amf_name_present); TESTASSERT(amf_upd->amf_name_present);
TESTASSERT(amf_name.id == 1); TESTASSERT_EQ(1, amf_name.id);
TESTASSERT(amf_name.crit == crit_opts::reject); TESTASSERT_EQ(crit_opts::reject, amf_name.crit);
TESTASSERT(amf_name.value.size() == 1); TESTASSERT_EQ("srsran", amf_name.value.to_string());
TESTASSERT(amf_name.value[0] == 17);
TESTASSERT(ceil(bref.distance_bytes()) == sizeof(ngap_msg));
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
// json_writer js; TESTASSERT_EQ(sizeof(ngap_msg), ceil(bref.distance_bytes()));
// pdu.to_json(js); TESTASSERT_EQ(SRSASN_SUCCESS, test_pack_unpack_consistency(pdu));
// printf("PDU json: %s\n", js.to_string().c_str());
json_writer js;
pdu.to_json(js);
printf("PDU json: %s\n", js.to_string().c_str());
return 0; return 0;
} }
@ -79,30 +79,29 @@ int test_ngsetup_request()
ng_setup_request_s& ngsetup = pdu.init_msg().value.ng_setup_request(); ng_setup_request_s& ngsetup = pdu.init_msg().value.ng_setup_request();
TESTASSERT(not ngsetup.ext); TESTASSERT(not ngsetup.ext);
// Field 0 // Field 0
TESTASSERT(ngsetup.protocol_ies.global_ran_node_id.id == 27); TESTASSERT(ngsetup->global_ran_node_id.id == 27);
TESTASSERT(ngsetup.protocol_ies.global_ran_node_id.crit.value == crit_opts::reject); TESTASSERT(ngsetup->global_ran_node_id.crit.value == crit_opts::reject);
TESTASSERT(ngsetup.protocol_ies.global_ran_node_id.value.type().value == TESTASSERT(ngsetup->global_ran_node_id.value.type().value == global_ran_node_id_c::types_opts::global_gnb_id);
global_ran_node_id_c::types_opts::global_gnb_id); global_gnb_id_s& global_gnb = ngsetup->global_ran_node_id.value.global_gnb_id();
global_gnb_id_s& global_gnb = ngsetup.protocol_ies.global_ran_node_id.value.global_gnb_id();
TESTASSERT(global_gnb.plmn_id.to_number() == 0xF110); TESTASSERT(global_gnb.plmn_id.to_number() == 0xF110);
TESTASSERT(global_gnb.gnb_id.type().value == gnb_id_c::types_opts::gnb_id); TESTASSERT(global_gnb.gnb_id.type().value == gnb_id_c::types_opts::gnb_id);
TESTASSERT(global_gnb.gnb_id.gnb_id().to_number() == 1); TESTASSERT(global_gnb.gnb_id.gnb_id().to_number() == 1);
// Field 1 // Field 1
TESTASSERT(ngsetup.protocol_ies.ran_node_name_present); TESTASSERT(ngsetup->ran_node_name_present);
// Field 2 // Field 2
TESTASSERT(ngsetup.protocol_ies.supported_ta_list.id == 102); TESTASSERT(ngsetup->supported_ta_list.id == 102);
TESTASSERT(ngsetup.protocol_ies.supported_ta_list.crit.value == crit_opts::reject); TESTASSERT(ngsetup->supported_ta_list.crit.value == crit_opts::reject);
TESTASSERT(ngsetup.protocol_ies.supported_ta_list.value.size() == 1); TESTASSERT(ngsetup->supported_ta_list.value.size() == 1);
TESTASSERT(ngsetup.protocol_ies.supported_ta_list.value[0].tac.to_number() == 0x75); TESTASSERT(ngsetup->supported_ta_list.value[0].tac.to_number() == 0x75);
TESTASSERT(ngsetup.protocol_ies.supported_ta_list.value[0].broadcast_plmn_list.size() == 1); TESTASSERT(ngsetup->supported_ta_list.value[0].broadcast_plmn_list.size() == 1);
auto& bcast_item = ngsetup.protocol_ies.supported_ta_list.value[0].broadcast_plmn_list[0]; auto& bcast_item = ngsetup->supported_ta_list.value[0].broadcast_plmn_list[0];
TESTASSERT(bcast_item.plmn_id.to_number() == 0xF110); TESTASSERT(bcast_item.plmn_id.to_number() == 0xF110);
TESTASSERT(bcast_item.tai_slice_support_list.size()); TESTASSERT(bcast_item.tai_slice_support_list.size());
TESTASSERT(bcast_item.tai_slice_support_list[0].s_nssai.sst.to_number() == 1); TESTASSERT(bcast_item.tai_slice_support_list[0].s_nssai.sst.to_number() == 1);
// Field 3 // Field 3
TESTASSERT(ngsetup.protocol_ies.default_paging_drx.id == 21); TESTASSERT(ngsetup->default_paging_drx.id == 21);
TESTASSERT(ngsetup.protocol_ies.default_paging_drx.crit.value == crit_opts::ignore); TESTASSERT(ngsetup->default_paging_drx.crit.value == crit_opts::ignore);
TESTASSERT(ngsetup.protocol_ies.default_paging_drx.value.value == paging_drx_opts::v256); TESTASSERT(ngsetup->default_paging_drx.value.value == paging_drx_opts::v256);
TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg)); TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg));
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
@ -137,19 +136,18 @@ int test_ngsetup_response()
ngap_elem_procs_o::successful_outcome_c::types_opts::ng_setup_resp); ngap_elem_procs_o::successful_outcome_c::types_opts::ng_setup_resp);
ng_setup_resp_s& resp = pdu.successful_outcome().value.ng_setup_resp(); ng_setup_resp_s& resp = pdu.successful_outcome().value.ng_setup_resp();
// field 0 // field 0
TESTASSERT(resp.protocol_ies.amf_name.id == 1); TESTASSERT(resp->amf_name.id == 1);
TESTASSERT(resp.protocol_ies.amf_name.crit.value == crit_opts::reject); TESTASSERT(resp->amf_name.crit.value == crit_opts::reject);
TESTASSERT(resp.protocol_ies.amf_name.value.size() == 56); TESTASSERT(resp->amf_name.value.size() == 56);
TESTASSERT(resp.protocol_ies.amf_name.value.to_string() == TESTASSERT(resp->amf_name.value.to_string() == "amf1.cluster1.net2.amf.5gc.mnc001.mcc001.3gppnetwork.org");
"amf1.cluster1.net2.amf.5gc.mnc001.mcc001.3gppnetwork.org");
// field 1 // field 1
TESTASSERT(resp.protocol_ies.served_guami_list.id == 96); TESTASSERT(resp->served_guami_list.id == 96);
TESTASSERT(resp.protocol_ies.served_guami_list.crit.value == crit_opts::reject); TESTASSERT(resp->served_guami_list.crit.value == crit_opts::reject);
TESTASSERT(resp.protocol_ies.served_guami_list.value.size() == 1); TESTASSERT(resp->served_guami_list.value.size() == 1);
TESTASSERT(resp.protocol_ies.served_guami_list.value[0].guami.plmn_id.to_number() == 0xF110); TESTASSERT(resp->served_guami_list.value[0].guami.plmn_id.to_number() == 0xF110);
TESTASSERT(resp.protocol_ies.served_guami_list.value[0].guami.amf_region_id.to_number() == 0b111000); TESTASSERT(resp->served_guami_list.value[0].guami.amf_region_id.to_number() == 0b111000);
TESTASSERT(resp.protocol_ies.served_guami_list.value[0].guami.amf_set_id.to_number() == 0b100010); TESTASSERT(resp->served_guami_list.value[0].guami.amf_set_id.to_number() == 0b100010);
TESTASSERT(resp.protocol_ies.served_guami_list.value[0].guami.amf_pointer.to_number() == 0b10111); TESTASSERT(resp->served_guami_list.value[0].guami.amf_pointer.to_number() == 0b10111);
// field 2 // field 2
// ... // ...
@ -181,7 +179,7 @@ int test_init_ue_msg()
TESTASSERT(pdu.init_msg().proc_code == 15); TESTASSERT(pdu.init_msg().proc_code == 15);
TESTASSERT(pdu.init_msg().crit.value == crit_opts::ignore); TESTASSERT(pdu.init_msg().crit.value == crit_opts::ignore);
TESTASSERT(pdu.init_msg().value.type().value == ngap_elem_procs_o::init_msg_c::types_opts::init_ue_msg); TESTASSERT(pdu.init_msg().value.type().value == ngap_elem_procs_o::init_msg_c::types_opts::init_ue_msg);
auto& container = pdu.init_msg().value.init_ue_msg().protocol_ies; auto& container = *pdu.init_msg().value.init_ue_msg();
// Field 0 // Field 0
TESTASSERT(container.ran_ue_ngap_id.id == 85); TESTASSERT(container.ran_ue_ngap_id.id == 85);
TESTASSERT(container.ran_ue_ngap_id.crit.value == crit_opts::reject); TESTASSERT(container.ran_ue_ngap_id.crit.value == crit_opts::reject);
@ -220,7 +218,7 @@ int test_dl_nas_transport()
// Field 0 // Field 0
// ... // ...
// Field 1 // Field 1
TESTASSERT(dl_nas.protocol_ies.nas_pdu.value.size() == 42); TESTASSERT(dl_nas->nas_pdu.value.size() == 42);
TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg)); TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg));
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
@ -246,7 +244,7 @@ int test_ul_ran_status_transfer()
TESTASSERT(pdu.init_msg().value.type().value == ngap_elem_procs_o::init_msg_c::types_opts::ul_nas_transport); TESTASSERT(pdu.init_msg().value.type().value == ngap_elem_procs_o::init_msg_c::types_opts::ul_nas_transport);
auto& ul_nas = pdu.init_msg().value.ul_nas_transport(); auto& ul_nas = pdu.init_msg().value.ul_nas_transport();
// Field 1 // Field 1
TESTASSERT(ul_nas.protocol_ies.nas_pdu.value.size() == 21); TESTASSERT(ul_nas->nas_pdu.value.size() == 21);
TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg)); TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg));
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
@ -317,10 +315,10 @@ int test_session_res_setup_request()
TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject); TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject);
TESTASSERT(pdu.init_msg().value.type().value == TESTASSERT(pdu.init_msg().value.type().value ==
ngap_elem_procs_o::init_msg_c::types_opts::pdu_session_res_setup_request); ngap_elem_procs_o::init_msg_c::types_opts::pdu_session_res_setup_request);
auto& container = pdu.init_msg().value.pdu_session_res_setup_request().protocol_ies; auto& container = pdu.init_msg().value.pdu_session_res_setup_request();
TESTASSERT(container.pdu_session_res_setup_list_su_req.id == ASN1_NGAP_ID_PDU_SESSION_RES_SETUP_LIST_SU_REQ); TESTASSERT(container->pdu_session_res_setup_list_su_req.id == ASN1_NGAP_ID_PDU_SESSION_RES_SETUP_LIST_SU_REQ);
TESTASSERT(container.pdu_session_res_setup_list_su_req.value.size() == 1); TESTASSERT(container->pdu_session_res_setup_list_su_req.value.size() == 1);
auto& item = container.pdu_session_res_setup_list_su_req.value[0]; auto& item = container->pdu_session_res_setup_list_su_req.value[0];
TESTASSERT(item.pdu_session_id == 1); TESTASSERT(item.pdu_session_id == 1);
TESTASSERT(item.s_nssai.sst.to_number() == 0); TESTASSERT(item.s_nssai.sst.to_number() == 0);
TESTASSERT(item.pdu_session_res_setup_request_transfer.to_string() == TESTASSERT(item.pdu_session_res_setup_request_transfer.to_string() ==
@ -330,10 +328,9 @@ int test_session_res_setup_request()
item.pdu_session_res_setup_request_transfer.size()); item.pdu_session_res_setup_request_transfer.size());
pdu_session_res_setup_request_transfer_s req; pdu_session_res_setup_request_transfer_s req;
TESTASSERT(req.unpack(bref2) == SRSASN_SUCCESS); TESTASSERT(req.unpack(bref2) == SRSASN_SUCCESS);
TESTASSERT(req.protocol_ies.ul_ngu_up_tnl_info.id == 139); TESTASSERT(req->ul_ngu_up_tnl_info.id == 139);
TESTASSERT(req.protocol_ies.ul_ngu_up_tnl_info.value.type().value == TESTASSERT(req->ul_ngu_up_tnl_info.value.type().value == up_transport_layer_info_c::types_opts::gtp_tunnel);
up_transport_layer_info_c::types_opts::gtp_tunnel); TESTASSERT(req->ul_ngu_up_tnl_info.value.gtp_tunnel().transport_layer_address.to_string() ==
TESTASSERT(req.protocol_ies.ul_ngu_up_tnl_info.value.gtp_tunnel().transport_layer_address.to_string() ==
"11000000101010000001000111010010"); "11000000101010000001000111010010");
TESTASSERT(bref2.distance_bytes() == (int)item.pdu_session_res_setup_request_transfer.size()); TESTASSERT(bref2.distance_bytes() == (int)item.pdu_session_res_setup_request_transfer.size());
@ -353,15 +350,15 @@ int main()
// Start the log backend. // Start the log backend.
srslog::init(); srslog::init();
TESTASSERT(test_amf_upd() == 0); test_amf_upd();
TESTASSERT(test_ngsetup_request() == 0); test_ngsetup_request();
TESTASSERT(test_ngsetup_response() == 0); test_ngsetup_response();
TESTASSERT(test_init_ue_msg() == 0); test_init_ue_msg();
TESTASSERT(test_dl_nas_transport() == 0); test_dl_nas_transport();
TESTASSERT(test_ul_ran_status_transfer() == 0); test_ul_ran_status_transfer();
TESTASSERT(test_ue_context_release() == 0); test_ue_context_release();
TESTASSERT(test_ue_context_release_complete() == 0); test_ue_context_release_complete();
TESTASSERT(test_session_res_setup_request() == 0); test_session_res_setup_request();
srslog::flush(); srslog::flush();

@ -687,8 +687,7 @@ int fill_phy_pdsch_cfg_common_test()
// "startSymbolAndLength": 40 // "startSymbolAndLength": 40
// ] // ]
asn1::rrc_nr::pdsch_cfg_common_s pdsch_cfg = {}; asn1::rrc_nr::pdsch_cfg_common_s pdsch_cfg = {};
pdsch_cfg.pdsch_time_domain_alloc_list_present = true;
pdsch_cfg.pdsch_time_domain_alloc_list.resize(1); pdsch_cfg.pdsch_time_domain_alloc_list.resize(1);
pdsch_cfg.pdsch_time_domain_alloc_list[0].map_type = pdsch_cfg.pdsch_time_domain_alloc_list[0].map_type =
asn1::rrc_nr::pdsch_time_domain_res_alloc_s::map_type_opts::options::type_a; asn1::rrc_nr::pdsch_time_domain_res_alloc_s::map_type_opts::options::type_a;
@ -743,8 +742,7 @@ int fill_phy_pusch_cfg_common_test()
// ], // ],
// "p0-NominalWithGrant": -76 // "p0-NominalWithGrant": -76
asn1::rrc_nr::pusch_cfg_common_s pusch_cfg = {}; asn1::rrc_nr::pusch_cfg_common_s pusch_cfg = {};
pusch_cfg.pusch_time_domain_alloc_list_present = true;
pusch_cfg.pusch_time_domain_alloc_list.resize(1); pusch_cfg.pusch_time_domain_alloc_list.resize(1);
pusch_cfg.pusch_time_domain_alloc_list[0].map_type = pusch_cfg.pusch_time_domain_alloc_list[0].map_type =
asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::options::type_a; asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::options::type_a;
@ -803,7 +801,6 @@ int fill_phy_carrier_cfg_test()
asn1::rrc_nr::subcarrier_spacing_opts::options::khz15; asn1::rrc_nr::subcarrier_spacing_opts::options::khz15;
serv_cell_cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = 52; serv_cell_cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = 52;
serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list_present = true;
serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list.resize(1); serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list.resize(1);
serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list[0].freq_band_ind_nr_present = true; serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list[0].freq_band_ind_nr_present = true;
serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list[0].freq_band_ind_nr = 3; serv_cell_cfg.ul_cfg_common.freq_info_ul.freq_band_list[0].freq_band_ind_nr = 3;

@ -48,10 +48,10 @@ int test_s1setup_request()
TESTASSERT(init_choice.type().value == s1ap_elem_procs_o::init_msg_c::types_opts::s1_setup_request); TESTASSERT(init_choice.type().value == s1ap_elem_procs_o::init_msg_c::types_opts::s1_setup_request);
s1_setup_request_s& s1req = init_choice.s1_setup_request(); s1_setup_request_s& s1req = init_choice.s1_setup_request();
TESTASSERT(not s1req.ext); TESTASSERT(not s1req.ext);
TESTASSERT(s1req.protocol_ies.global_enb_id.id == ASN1_S1AP_ID_GLOBAL_ENB_ID); TESTASSERT(s1req->global_enb_id.id == ASN1_S1AP_ID_GLOBAL_ENB_ID);
TESTASSERT(s1req.protocol_ies.global_enb_id.crit.value == crit_opts::reject); TESTASSERT(s1req->global_enb_id.crit.value == crit_opts::reject);
TESTASSERT(s1req.protocol_ies.global_enb_id.value.enb_id.type().value == enb_id_c::types_opts::macro_enb_id); TESTASSERT(s1req->global_enb_id.value.enb_id.type().value == enb_id_c::types_opts::macro_enb_id);
TESTASSERT(s1req.protocol_ies.global_enb_id.value.enb_id.macro_enb_id().to_number() == 0x0019B); TESTASSERT(s1req->global_enb_id.value.enb_id.macro_enb_id().to_number() == 0x0019B);
// //
// // json_writer js; // // json_writer js;
// // pdu.to_json(js); // // pdu.to_json(js);
@ -86,10 +86,10 @@ int test_init_ctxt_setup_req()
TESTASSERT(pdu.init_msg().proc_code == 9); TESTASSERT(pdu.init_msg().proc_code == 9);
TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject); TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject);
s1ap_elem_procs_o::init_msg_c& init_choice = pdu.init_msg().value; s1ap_elem_procs_o::init_msg_c& init_choice = pdu.init_msg().value;
auto& ctxt_setup = init_choice.init_context_setup_request().protocol_ies; auto& ctxt_setup = init_choice.init_context_setup_request();
TESTASSERT(ctxt_setup.ue_security_cap.id == 107); TESTASSERT(ctxt_setup->ue_security_cap.id == 107);
TESTASSERT(ctxt_setup.ue_security_cap.value.encryption_algorithms.to_string() == "1100000000000000"); TESTASSERT(ctxt_setup->ue_security_cap.value.encryption_algorithms.to_string() == "1100000000000000");
TESTASSERT(ctxt_setup.ue_security_cap.value.integrity_protection_algorithms.to_string() == "1100000000000000"); TESTASSERT(ctxt_setup->ue_security_cap.value.integrity_protection_algorithms.to_string() == "1100000000000000");
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
@ -108,11 +108,11 @@ int test_ue_ctxt_release_req()
TESTASSERT(pdu.type().value == s1ap_pdu_c::types_opts::init_msg); TESTASSERT(pdu.type().value == s1ap_pdu_c::types_opts::init_msg);
TESTASSERT(pdu.init_msg().proc_code == ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST); TESTASSERT(pdu.init_msg().proc_code == ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST);
auto& req = pdu.init_msg().value.ue_context_release_request().protocol_ies; auto& req = pdu.init_msg().value.ue_context_release_request();
TESTASSERT(req.mme_ue_s1ap_id.value.value == 1); TESTASSERT(req->mme_ue_s1ap_id.value.value == 1);
TESTASSERT(req.enb_ue_s1ap_id.value.value == 1); TESTASSERT(req->enb_ue_s1ap_id.value.value == 1);
TESTASSERT(req.cause.value.type().value == cause_c::types_opts::radio_network); TESTASSERT(req->cause.value.type().value == cause_c::types_opts::radio_network);
TESTASSERT(req.cause.value.radio_network().value == cause_radio_network_opts::user_inactivity); TESTASSERT(req->cause.value.radio_network().value == cause_radio_network_opts::user_inactivity);
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
@ -187,9 +187,9 @@ int test_ho_request()
TESTASSERT(pdu.type().value == s1ap_pdu_c::types_opts::init_msg); TESTASSERT(pdu.type().value == s1ap_pdu_c::types_opts::init_msg);
TESTASSERT(pdu.init_msg().proc_code == ASN1_S1AP_ID_HO_RES_ALLOC); TESTASSERT(pdu.init_msg().proc_code == ASN1_S1AP_ID_HO_RES_ALLOC);
TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject); TESTASSERT(pdu.init_msg().crit.value == crit_opts::reject);
auto& horeq = pdu.init_msg().value.ho_request().protocol_ies; auto& horeq = pdu.init_msg().value.ho_request();
auto& erab_item = horeq.erab_to_be_setup_list_ho_req.value[0].value.erab_to_be_setup_item_ho_req(); auto& erab_item = horeq->erab_to_be_setup_list_ho_req.value[0]->erab_to_be_setup_item_ho_req();
TESTASSERT(erab_item.erab_id == 5); TESTASSERT(erab_item.erab_id == 5);
TESTASSERT(erab_item.gtp_teid.to_string() == "b7361c56"); TESTASSERT(erab_item.gtp_teid.to_string() == "b7361c56");
@ -203,15 +203,16 @@ int test_enb_status_transfer()
s1ap_pdu_c pdu; s1ap_pdu_c pdu;
TESTASSERT(pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ENB_STATUS_TRANSFER)); TESTASSERT(pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ENB_STATUS_TRANSFER));
auto& enb_status_transfer = pdu.init_msg().value.enb_status_transfer().protocol_ies; auto& enb_status_transfer = pdu.init_msg().value.enb_status_transfer();
enb_status_transfer.mme_ue_s1ap_id.value.value = 1; enb_status_transfer->mme_ue_s1ap_id.value.value = 1;
enb_status_transfer.enb_ue_s1ap_id.value.value = 1; enb_status_transfer->enb_ue_s1ap_id.value.value = 1;
enb_status_transfer.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list.resize(1); enb_status_transfer->enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list.resize(
1);
auto& bearer = auto& bearer =
enb_status_transfer.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list[0]; enb_status_transfer->enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list[0];
TESTASSERT(bearer.load_info_obj(ASN1_S1AP_ID_BEARERS_SUBJECT_TO_STATUS_TRANSFER_ITEM)); TESTASSERT(bearer.load_info_obj(ASN1_S1AP_ID_BEARERS_SUBJECT_TO_STATUS_TRANSFER_ITEM));
auto& bearer_item = bearer.value.bearers_subject_to_status_transfer_item(); auto& bearer_item = bearer->bearers_subject_to_status_transfer_item();
bearer_item.erab_id = 5; bearer_item.erab_id = 5;
bearer_item.dl_coun_tvalue.pdcp_sn = 5; bearer_item.dl_coun_tvalue.pdcp_sn = 5;
@ -230,11 +231,10 @@ int test_enb_status_transfer()
s1ap_pdu_c pdu2; s1ap_pdu_c pdu2;
TESTASSERT(pdu2.unpack(bref2) == SRSASN_SUCCESS); TESTASSERT(pdu2.unpack(bref2) == SRSASN_SUCCESS);
auto& bearer2 = auto& bearer2 = pdu2.init_msg()
pdu2.init_msg() .value.enb_status_transfer()
.value.enb_status_transfer() ->enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list[0];
.protocol_ies.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list[0]; auto& bearer_item2 = bearer2->bearers_subject_to_status_transfer_item();
auto& bearer_item2 = bearer2.value.bearers_subject_to_status_transfer_item();
TESTASSERT(bearer_item2.dl_coun_tvalue.hfn == bearer_item.dl_coun_tvalue.hfn); TESTASSERT(bearer_item2.dl_coun_tvalue.hfn == bearer_item.dl_coun_tvalue.hfn);
TESTASSERT(bearer_item2.dl_coun_tvalue.hfn == 0); TESTASSERT(bearer_item2.dl_coun_tvalue.hfn == 0);
@ -264,7 +264,7 @@ int test_load_info_obj()
container.erab_failed_to_setup_list_ctxt_su_res.value.resize(1); container.erab_failed_to_setup_list_ctxt_su_res.value.resize(1);
container.erab_failed_to_setup_list_ctxt_su_res.value[0].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); container.erab_failed_to_setup_list_ctxt_su_res.value[0].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
TESTASSERT(container.erab_failed_to_setup_list_ctxt_su_res.value[0].id == ASN1_S1AP_ID_ERAB_ITEM); TESTASSERT_EQ(ASN1_S1AP_ID_ERAB_ITEM, container.erab_failed_to_setup_list_ctxt_su_res.value[0].id());
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -276,15 +276,15 @@ int test_initial_ctxt_setup_response()
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP);
// Fill in the MME and eNB IDs // Fill in the MME and eNB IDs
auto& container = tx_pdu.successful_outcome().value.init_context_setup_resp().protocol_ies; auto& container = tx_pdu.successful_outcome().value.init_context_setup_resp();
container.mme_ue_s1ap_id.value = 1; container->mme_ue_s1ap_id.value = 1;
container.enb_ue_s1ap_id.value = 1; container->enb_ue_s1ap_id.value = 1;
container.erab_setup_list_ctxt_su_res.value.resize(1); container->erab_setup_list_ctxt_su_res.value.resize(1);
// Fill in the GTP bind address for all bearers // Fill in the GTP bind address for all bearers
for (uint32_t i = 0; i < container.erab_setup_list_ctxt_su_res.value.size(); ++i) { for (uint32_t i = 0; i < container->erab_setup_list_ctxt_su_res.value.size(); ++i) {
container.erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES); container->erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES);
auto& item = container.erab_setup_list_ctxt_su_res.value[i].value.erab_setup_item_ctxt_su_res(); auto& item = container->erab_setup_list_ctxt_su_res.value[i]->erab_setup_item_ctxt_su_res();
item.erab_id = 1; item.erab_id = 1;
// uint32_to_uint8(teid_in, item.gtp_teid.data()); // uint32_to_uint8(teid_in, item.gtp_teid.data());
item.transport_layer_address.resize(32); item.transport_layer_address.resize(32);

@ -75,7 +75,6 @@ int test_eutra_nr_capabilities()
band_combination.band_list.push_back(band_param_nr); band_combination.band_list.push_back(band_param_nr);
mrdc_cap.rf_params_mrdc.supported_band_combination_list.push_back(band_combination); mrdc_cap.rf_params_mrdc.supported_band_combination_list.push_back(band_combination);
mrdc_cap.rf_params_mrdc.supported_band_combination_list_present = true;
mrdc_cap.rf_params_mrdc.ext = true; mrdc_cap.rf_params_mrdc.ext = true;
@ -92,8 +91,6 @@ int test_eutra_nr_capabilities()
band_info_nr.band_info_nr().band_nr = 78; band_info_nr.band_info_nr().band_nr = 78;
mrdc_cap.rf_params_mrdc.applied_freq_band_list_filt.push_back(band_info_nr); mrdc_cap.rf_params_mrdc.applied_freq_band_list_filt.push_back(band_info_nr);
mrdc_cap.rf_params_mrdc.applied_freq_band_list_filt_present = true;
// rf_params_mrdc supported band combination list v1540 // rf_params_mrdc supported band combination list v1540
band_combination_list_v1540_l* band_combination_list_v1450 = new band_combination_list_v1540_l(); band_combination_list_v1540_l* band_combination_list_v1450 = new band_combination_list_v1540_l();
@ -146,8 +143,6 @@ int test_eutra_nr_capabilities()
mrdc_cap.feature_set_combinations.push_back(feature_set_combination); mrdc_cap.feature_set_combinations.push_back(feature_set_combination);
mrdc_cap.feature_set_combinations_present = true;
// Pack mrdc_cap // Pack mrdc_cap
uint8_t buffer[1024]; uint8_t buffer[1024];
asn1::bit_ref bref(buffer, sizeof(buffer)); asn1::bit_ref bref(buffer, sizeof(buffer));
@ -218,7 +213,7 @@ int test_ue_rrc_reconfiguration()
#endif #endif
TESTASSERT(rrc_recfg.crit_exts.type() == asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg); TESTASSERT(rrc_recfg.crit_exts.type() == asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg);
TESTASSERT(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group_present == true); TESTASSERT(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.size() > 0);
cell_group_cfg_s cell_group_cfg; cell_group_cfg_s cell_group_cfg;
cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(), cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(),
@ -230,7 +225,6 @@ int test_ue_rrc_reconfiguration()
srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: \n %s", jw1.to_string().c_str()); srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: \n %s", jw1.to_string().c_str());
#endif #endif
TESTASSERT(cell_group_cfg.cell_group_id == 1); TESTASSERT(cell_group_cfg.cell_group_id == 1);
TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list_present == true);
TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list.size() == 1); TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list.size() == 1);
TESTASSERT(cell_group_cfg.mac_cell_group_cfg_present == true); TESTASSERT(cell_group_cfg.mac_cell_group_cfg_present == true);
TESTASSERT(cell_group_cfg.phys_cell_group_cfg_present == true); TESTASSERT(cell_group_cfg.phys_cell_group_cfg_present == true);
@ -249,7 +243,6 @@ int test_radio_bearer_config()
radio_bearer_cfg.to_json(jw); radio_bearer_cfg.to_json(jw);
srslog::fetch_basic_logger("RRC").info("RRC Bearer CFG Message: \n %s", jw.to_string().c_str()); srslog::fetch_basic_logger("RRC").info("RRC Bearer CFG Message: \n %s", jw.to_string().c_str());
#endif #endif
TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list_present == true);
TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list.size() == 1); TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list.size() == 1);
TESTASSERT(radio_bearer_cfg.security_cfg_present == true); TESTASSERT(radio_bearer_cfg.security_cfg_present == true);
TESTASSERT(radio_bearer_cfg.security_cfg.security_algorithm_cfg_present == true); TESTASSERT(radio_bearer_cfg.security_cfg.security_algorithm_cfg_present == true);
@ -260,8 +253,7 @@ int test_radio_bearer_config()
reconfig.rrc_transaction_id = 0; reconfig.rrc_transaction_id = 0;
rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.set_rrc_recfg(); rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.set_rrc_recfg();
recfg_ies.radio_bearer_cfg_present = true; recfg_ies.radio_bearer_cfg_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list.resize(1); recfg_ies.radio_bearer_cfg.drb_to_add_mod_list.resize(1);
auto& drb_item = recfg_ies.radio_bearer_cfg.drb_to_add_mod_list[0]; auto& drb_item = recfg_ies.radio_bearer_cfg.drb_to_add_mod_list[0];
@ -371,9 +363,8 @@ int test_cell_group_config_tdd()
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present == cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present ==
true); true);
TESTASSERT( TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.type() == .is_setup());
asn1::rrc_nr::setup_release_c<rach_cfg_common_s>::types_opts::setup);
asn1::rrc_nr::rach_cfg_common_s& rach_cfg_common = asn1::rrc_nr::rach_cfg_common_s& rach_cfg_common =
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(); cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup();
@ -399,7 +390,6 @@ int test_cell_group_config_tdd()
cell_group_cfg_s cell_group_cfg_pack; cell_group_cfg_s cell_group_cfg_pack;
// RLC for DRB1 // RLC for DRB1
cell_group_cfg_pack.rlc_bearer_to_add_mod_list_present = true;
cell_group_cfg_pack.rlc_bearer_to_add_mod_list.resize(1); cell_group_cfg_pack.rlc_bearer_to_add_mod_list.resize(1);
auto& rlc = cell_group_cfg_pack.rlc_bearer_to_add_mod_list[0]; auto& rlc = cell_group_cfg_pack.rlc_bearer_to_add_mod_list[0];
rlc.lc_ch_id = 1; rlc.lc_ch_id = 1;
@ -428,10 +418,9 @@ int test_cell_group_config_tdd()
rlc.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0; rlc.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0;
// mac-CellGroup-Config // mac-CellGroup-Config
cell_group_cfg_pack.mac_cell_group_cfg_present = true; cell_group_cfg_pack.mac_cell_group_cfg_present = true;
auto& mac_cell_group = cell_group_cfg_pack.mac_cell_group_cfg; auto& mac_cell_group = cell_group_cfg_pack.mac_cell_group_cfg;
mac_cell_group.sched_request_cfg_present = true; mac_cell_group.sched_request_cfg_present = true;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list_present = true;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list.resize(1); mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list.resize(1);
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sched_request_id = 0; mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sched_request_id = 0;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sr_trans_max = mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sr_trans_max =
@ -452,7 +441,6 @@ int test_cell_group_config_tdd()
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true;
auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg; auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg;
pdcch_cfg_dedicated.set_setup(); pdcch_cfg_dedicated.set_setup();
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list_present = true;
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1); pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1);
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2; pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2;
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number( pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number(
@ -463,7 +451,6 @@ int test_cell_group_config_tdd()
asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle;
// search spaces // search spaces
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list_present = true;
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1); pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1);
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2; pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2;
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true; pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true;
@ -498,7 +485,6 @@ int test_cell_group_config_tdd()
pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true; pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true;
pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position = pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position =
asn1::rrc_nr::dmrs_dl_cfg_s::dmrs_add_position_opts::pos1; asn1::rrc_nr::dmrs_dl_cfg_s::dmrs_add_position_opts::pos1;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list_present = true;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list.resize(1); pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list.resize(1);
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].tci_state_id = 0; pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].tci_state_id = 0;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb(); pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb();
@ -513,7 +499,6 @@ int test_cell_group_config_tdd()
asn1::rrc_nr::pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband; asn1::rrc_nr::pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband;
// ZP-CSI // ZP-CSI
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list_present = true;
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list.resize(1); pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list.resize(1);
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0; pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0;
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4(); pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4();
@ -552,7 +537,6 @@ int test_cell_group_config_tdd()
ul_config.init_ul_bwp.pucch_cfg.setup().format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25; ul_config.init_ul_bwp.pucch_cfg.setup().format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25;
// SR resources // SR resources
ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list.resize(1); ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list.resize(1);
auto& sr_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list[0]; auto& sr_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list[0];
sr_res1.sched_request_res_id = 1; sr_res1.sched_request_res_id = 1;
@ -564,7 +548,6 @@ int test_cell_group_config_tdd()
sr_res1.res = 0; // only PUCCH resource we have defined so far sr_res1.res = 0; // only PUCCH resource we have defined so far
// DL data // DL data
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack.resize(5); ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack.resize(5);
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[0] = 8; ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[0] = 8;
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[1] = 7; ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[1] = 7;
@ -573,7 +556,6 @@ int test_cell_group_config_tdd()
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[4] = 4; ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[4] = 4;
// PUCCH resources (only one format1 for the moment) // PUCCH resources (only one format1 for the moment)
ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list.resize(1); ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list.resize(1);
auto& pucch_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list[0]; auto& pucch_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list[0];
pucch_res1.pucch_res_id = 0; pucch_res1.pucch_res_id = 0;
@ -635,7 +617,6 @@ int test_cell_group_config_tdd()
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup(); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup();
// nzp-CSI-RS Resource // nzp-CSI-RS Resource
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list.resize(1); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list.resize(1);
auto& nzp_csi_res = auto& nzp_csi_res =
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list[0]; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list[0];
@ -659,8 +640,6 @@ int test_cell_group_config_tdd()
nzp_csi_res.qcl_info_periodic_csi_rs = 0; nzp_csi_res.qcl_info_periodic_csi_rs = 0;
// nzp-CSI-RS ResourceSet // nzp-CSI-RS ResourceSet
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list_present =
true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list.resize(1); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list.resize(1);
auto& nzp_csi_res_set = auto& nzp_csi_res_set =
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list[0]; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list[0];
@ -670,7 +649,6 @@ int test_cell_group_config_tdd()
// Skip TRS info // Skip TRS info
// CSI report config // CSI report config
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list.resize(1); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list.resize(1);
auto& csi_report = auto& csi_report =
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list[0]; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list[0];
@ -753,7 +731,6 @@ int test_cell_group_config_tdd()
asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle;
// common search space list // common search space list
pdcch_cfg_common.setup().common_search_space_list_present = true;
pdcch_cfg_common.setup().common_search_space_list.resize(1); pdcch_cfg_common.setup().common_search_space_list.resize(1);
pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1; pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1;
pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true; pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true;
@ -789,7 +766,6 @@ int test_cell_group_config_tdd()
.set_setup(); .set_setup();
auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp
.pdsch_cfg_common.setup(); .pdsch_cfg_common.setup();
pdsch_cfg_common.pdsch_time_domain_alloc_list_present = true;
pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1); pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1);
pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a; pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a;
pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40; pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40;
@ -843,7 +819,6 @@ int test_cell_group_config_tdd()
auto& pusch_cfg_common_pack = auto& pusch_cfg_common_pack =
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common; cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common;
pusch_cfg_common_pack.set_setup(); pusch_cfg_common_pack.set_setup();
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list_present = true;
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2); pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2);
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true; pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true;
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4; pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4;
@ -989,9 +964,8 @@ int test_cell_group_config_fdd()
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present == cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present ==
true); true);
TESTASSERT( TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.type() == .is_setup());
asn1::rrc_nr::setup_release_c<rach_cfg_common_s>::types_opts::setup);
asn1::rrc_nr::rach_cfg_common_s& rach_cfg_common = asn1::rrc_nr::rach_cfg_common_s& rach_cfg_common =
cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(); cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup();
@ -1017,7 +991,6 @@ int test_cell_group_config_fdd()
cell_group_cfg_s cell_group_cfg_pack; cell_group_cfg_s cell_group_cfg_pack;
// RLC for DRB1 // RLC for DRB1
cell_group_cfg_pack.rlc_bearer_to_add_mod_list_present = true;
cell_group_cfg_pack.rlc_bearer_to_add_mod_list.resize(1); cell_group_cfg_pack.rlc_bearer_to_add_mod_list.resize(1);
auto& rlc = cell_group_cfg_pack.rlc_bearer_to_add_mod_list[0]; auto& rlc = cell_group_cfg_pack.rlc_bearer_to_add_mod_list[0];
rlc.lc_ch_id = 4; rlc.lc_ch_id = 4;
@ -1046,10 +1019,9 @@ int test_cell_group_config_fdd()
rlc.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0; rlc.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0;
// mac-CellGroup-Config // mac-CellGroup-Config
cell_group_cfg_pack.mac_cell_group_cfg_present = true; cell_group_cfg_pack.mac_cell_group_cfg_present = true;
auto& mac_cell_group = cell_group_cfg_pack.mac_cell_group_cfg; auto& mac_cell_group = cell_group_cfg_pack.mac_cell_group_cfg;
mac_cell_group.sched_request_cfg_present = true; mac_cell_group.sched_request_cfg_present = true;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list_present = true;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list.resize(1); mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list.resize(1);
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sched_request_id = 0; mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sched_request_id = 0;
mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sr_trans_max = mac_cell_group.sched_request_cfg.sched_request_to_add_mod_list[0].sr_trans_max =
@ -1070,7 +1042,6 @@ int test_cell_group_config_fdd()
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true;
auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg; auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg;
pdcch_cfg_dedicated.set_setup(); pdcch_cfg_dedicated.set_setup();
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list_present = true;
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1); pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1);
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2; pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2;
pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number( pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number(
@ -1081,7 +1052,6 @@ int test_cell_group_config_fdd()
asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle;
// search spaces // search spaces
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list_present = true;
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1); pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1);
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2; pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2;
pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true; pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true;
@ -1116,7 +1086,6 @@ int test_cell_group_config_fdd()
pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true; pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true;
pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position = pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position =
asn1::rrc_nr::dmrs_dl_cfg_s::dmrs_add_position_opts::pos1; asn1::rrc_nr::dmrs_dl_cfg_s::dmrs_add_position_opts::pos1;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list_present = true;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list.resize(1); pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list.resize(1);
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].tci_state_id = 0; pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].tci_state_id = 0;
pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb(); pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb();
@ -1131,7 +1100,6 @@ int test_cell_group_config_fdd()
asn1::rrc_nr::pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband; asn1::rrc_nr::pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband;
// ZP-CSI // ZP-CSI
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list_present = true;
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list.resize(1); pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list.resize(1);
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0; pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0;
pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4(); pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4();
@ -1170,7 +1138,6 @@ int test_cell_group_config_fdd()
ul_config.init_ul_bwp.pucch_cfg.setup().format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25; ul_config.init_ul_bwp.pucch_cfg.setup().format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25;
// SR resources // SR resources
ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list.resize(1); ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list.resize(1);
auto& sr_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list[0]; auto& sr_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().sched_request_res_to_add_mod_list[0];
sr_res1.sched_request_res_id = 1; sr_res1.sched_request_res_id = 1;
@ -1182,13 +1149,11 @@ int test_cell_group_config_fdd()
sr_res1.res = 16; sr_res1.res = 16;
// DL data // DL data
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack.resize(1); ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack.resize(1);
ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[0] = 4; ul_config.init_ul_bwp.pucch_cfg.setup().dl_data_to_ul_ack[0] = 4;
// TODO? // TODO?
// PUCCH resources (only one format1 for the moment) // PUCCH resources (only one format1 for the moment)
ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list_present = true;
ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list.resize(1); ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list.resize(1);
auto& pucch_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list[0]; auto& pucch_res1 = ul_config.init_ul_bwp.pucch_cfg.setup().res_to_add_mod_list[0];
pucch_res1.pucch_res_id = 0; pucch_res1.pucch_res_id = 0;
@ -1250,7 +1215,6 @@ int test_cell_group_config_fdd()
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup(); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup();
// nzp-CSI-RS Resource // nzp-CSI-RS Resource
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list.resize(5); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_to_add_mod_list.resize(5);
auto& nzp_csi_res = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup(); auto& nzp_csi_res = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup();
// item 0 // item 0
@ -1360,8 +1324,6 @@ int test_cell_group_config_fdd()
nzp_csi_res.nzp_csi_rs_res_to_add_mod_list[4].qcl_info_periodic_csi_rs = 0; nzp_csi_res.nzp_csi_rs_res_to_add_mod_list[4].qcl_info_periodic_csi_rs = 0;
// nzp-CSI-RS ResourceSet // nzp-CSI-RS ResourceSet
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list_present =
true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list.resize(2); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().nzp_csi_rs_res_set_to_add_mod_list.resize(2);
auto& nzp_csi_res_set = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup(); auto& nzp_csi_res_set = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup();
// item 0 // item 0
@ -1384,7 +1346,6 @@ int test_cell_group_config_fdd()
// TODO: add csi resource config // TODO: add csi resource config
// CSI report config // CSI report config
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list.resize(1); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list.resize(1);
auto& csi_report = auto& csi_report =
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list[0]; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup().csi_report_cfg_to_add_mod_list[0];
@ -1467,7 +1428,6 @@ int test_cell_group_config_fdd()
asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle;
// common search space list // common search space list
pdcch_cfg_common.setup().common_search_space_list_present = true;
pdcch_cfg_common.setup().common_search_space_list.resize(1); pdcch_cfg_common.setup().common_search_space_list.resize(1);
pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1; pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1;
pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true; pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true;
@ -1503,7 +1463,6 @@ int test_cell_group_config_fdd()
.set_setup(); .set_setup();
auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp
.pdsch_cfg_common.setup(); .pdsch_cfg_common.setup();
pdsch_cfg_common.pdsch_time_domain_alloc_list_present = true;
pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1); pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1);
pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a; pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a;
pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40; pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40;
@ -1561,7 +1520,6 @@ int test_cell_group_config_fdd()
auto& pusch_cfg_common_pack = auto& pusch_cfg_common_pack =
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common; cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common;
pusch_cfg_common_pack.set_setup(); pusch_cfg_common_pack.set_setup();
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list_present = true;
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2); pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2);
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true; pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true;
pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4; pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4;

@ -53,7 +53,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
for (int i = 0; i < NBUFS; i++) { for (int i = 0; i < NBUFS; i++) {
uint32_t len = rlc->read_pdu(pdu_bufs[i].msg, 3); // 2 bytes for header + 1 byte payload uint32_t len = rlc->read_pdu(pdu_bufs[i].msg, 3); // 2 bytes for header + 1 byte payload
pdu_bufs[i].N_bytes = len; pdu_bufs[i].N_bytes = len;
TESTASSERT(3 == len); TESTASSERT_EQ(3, len);
} }
TESTASSERT(0 == rlc->get_buffer_state()); TESTASSERT(0 == rlc->get_buffer_state());
@ -137,12 +137,10 @@ int basic_test()
timer_handler timers(8); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; byte_buffer_t pdu_bufs[NBUFS];
auto& test_logger = srslog::fetch_basic_logger("TESTER "); auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_logger.info("===================="); test_delimit_logger delimiter("basic tx/rx");
test_logger.info("==== Basic Test ===="); rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
test_logger.info("===================="); rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
rlc_am_nr_tx* tx1 = dynamic_cast<rlc_am_nr_tx*>(rlc1.get_tx()); rlc_am_nr_tx* tx1 = dynamic_cast<rlc_am_nr_tx*>(rlc1.get_tx());
rlc_am_nr_rx* rx1 = dynamic_cast<rlc_am_nr_rx*>(rlc1.get_rx()); rlc_am_nr_rx* rx1 = dynamic_cast<rlc_am_nr_rx*>(rlc1.get_rx());
@ -231,12 +229,10 @@ int lost_pdu_test()
timer_handler timers(8); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; byte_buffer_t pdu_bufs[NBUFS];
auto& test_logger = srslog::fetch_basic_logger("TESTER "); auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_logger.info("======================="); rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
test_logger.info("==== Lost PDU Test ===="); rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
test_logger.info("======================="); test_delimit_logger delimiter("lost PDU");
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
// before configuring entity // before configuring entity
TESTASSERT(0 == rlc1.get_buffer_state()); TESTASSERT(0 == rlc1.get_buffer_state());
@ -350,6 +346,79 @@ int lost_pdu_test()
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
/*
* Test the basic segmentation of a single SDU.
* A single SDU of 3 bytes is segmented into 3 PDUs
*/
int basic_segmentation_test()
{
rlc_am_tester tester;
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_delimit_logger delimiter("basic segmentation");
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
// before configuring entity
TESTASSERT(0 == rlc1.get_buffer_state());
if (not rlc1.configure(rlc_config_t::default_rlc_am_nr_config())) {
return -1;
}
if (not rlc2.configure(rlc_config_t::default_rlc_am_nr_config())) {
return -1;
}
// Push 1 SDU into RLC1
unique_byte_buffer_t sdu;
sdu = srsran::make_byte_buffer();
TESTASSERT(nullptr != sdu);
sdu->msg[0] = 0; // Write the index into the buffer
sdu->N_bytes = 3; // Give the SDU the size of 3 bytes
sdu->md.pdcp_sn = 0; // PDCP SN for notifications
rlc1.write_sdu(std::move(sdu));
// Read 3 PDUs
constexpr uint16_t n_pdus = 3;
unique_byte_buffer_t pdu_bufs[n_pdus];
for (int i = 0; i < 3; i++) {
pdu_bufs[i] = srsran::make_byte_buffer();
TESTASSERT(nullptr != pdu_bufs[i]);
if (i == 0) {
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 3);
TESTASSERT_EQ(3, pdu_bufs[i]->N_bytes);
} else {
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 5);
TESTASSERT_EQ(5, pdu_bufs[i]->N_bytes);
}
}
// Write 5 PDUs into RLC2
for (int i = 0; i < n_pdus; i++) {
rlc2.write_pdu(pdu_bufs[i]->msg, pdu_bufs[i]->N_bytes); // Don't write RLC_SN=3.
}
// Check statistics
rlc_bearer_metrics_t metrics1 = rlc1.get_metrics();
rlc_bearer_metrics_t metrics2 = rlc2.get_metrics();
// SDU metrics
TESTASSERT_EQ(0, metrics2.num_tx_sdus);
TESTASSERT_EQ(1, metrics2.num_rx_sdus);
TESTASSERT_EQ(0, metrics2.num_tx_sdu_bytes);
TESTASSERT_EQ(3, metrics2.num_rx_sdu_bytes);
TESTASSERT_EQ(0, metrics2.num_lost_sdus);
// PDU metrics
TESTASSERT_EQ(0, metrics2.num_tx_pdus);
TESTASSERT_EQ(3, metrics2.num_rx_pdus); // 5 PDUs (6 tx'ed, but one was lost)
TESTASSERT_EQ(0, metrics2.num_tx_pdu_bytes); // Two status PDU (one with a NACK)
TESTASSERT_EQ(13, metrics2.num_rx_pdu_bytes); // 1 PDU (No SO) + 2 PDUs (with SO) = 3 + 2*5
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
// Setup the log message spy to intercept error and warning log entries from RLC // Setup the log message spy to intercept error and warning log entries from RLC
@ -372,12 +441,13 @@ int main(int argc, char** argv)
logger_rlc1.set_level(srslog::basic_levels::debug); logger_rlc1.set_level(srslog::basic_levels::debug);
logger_rlc2.set_level(srslog::basic_levels::debug); logger_rlc2.set_level(srslog::basic_levels::debug);
// start log backend // start log back-end
srslog::init(); srslog::init();
TESTASSERT(window_checker_test() == SRSRAN_SUCCESS); TESTASSERT(window_checker_test() == SRSRAN_SUCCESS);
TESTASSERT(basic_test() == SRSRAN_SUCCESS); TESTASSERT(basic_test() == SRSRAN_SUCCESS);
TESTASSERT(lost_pdu_test() == SRSRAN_SUCCESS); TESTASSERT(lost_pdu_test() == SRSRAN_SUCCESS);
TESTASSERT(basic_segmentation_test() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -854,8 +854,35 @@ static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& cellroot)
rrc_value_to_range(srsran::quant_rsrq, (int)root[i]["a4_thresh"]); rrc_value_to_range(srsran::quant_rsrq, (int)root[i]["a4_thresh"]);
} }
break; break;
case 5:
// a5-threshold1
if (!root[i].exists("a5_thresh1")) {
ERROR("Missing a5_thresh1 field for A5 event\n");
return SRSRAN_ERROR;
}
if (meas_item.trigger_quant == report_cfg_eutra_s::trigger_quant_opts::rsrp) {
event.event_id.set_event_a5().a5_thres1.set_thres_rsrp() =
rrc_value_to_range(srsran::quant_rsrp, (int)root[i]["a5_thresh1"]);
} else {
event.event_id.set_event_a5().a5_thres1.set_thres_rsrq() =
rrc_value_to_range(srsran::quant_rsrq, (int)root[i]["a5_thresh1"]);
}
// a5-threshold2
if (!root[i].exists("a5_thresh2")) {
ERROR("Missing a5_thresh2 field for A5 event\n");
return SRSRAN_ERROR;
}
if (meas_item.trigger_quant == report_cfg_eutra_s::trigger_quant_opts::rsrp) {
event.event_id.set_event_a5().a5_thres2.set_thres_rsrp() =
rrc_value_to_range(srsran::quant_rsrp, (int)root[i]["a5_thresh2"]);
} else {
event.event_id.set_event_a5().a5_thres2.set_thres_rsrq() =
rrc_value_to_range(srsran::quant_rsrq, (int)root[i]["a5_thresh2"]);
}
break;
default: default:
ERROR("Invalid or unsupported event A%d in meas_report_desc (only A1-A4 are supported)\n", ERROR("Invalid or unsupported event A%d in meas_report_desc (only A1-A5 are supported)\n",
(int)root[i]["eventA"]); (int)root[i]["eventA"]);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -907,6 +934,7 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
HANDLEPARSERCODE(parse_required_field(cell_cfg.cell_id, cellroot, "cell_id")); HANDLEPARSERCODE(parse_required_field(cell_cfg.cell_id, cellroot, "cell_id"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac")); HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.pci, cellroot, "pci")); HANDLEPARSERCODE(parse_required_field(cell_cfg.pci, cellroot, "pci"));
parse_default_field(cell_cfg.tx_gain, cellroot, "tx_gain", 0.0);
cell_cfg.pci = cell_cfg.pci % SRSRAN_NUM_PCI; cell_cfg.pci = cell_cfg.pci % SRSRAN_NUM_PCI;
HANDLEPARSERCODE(parse_required_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn")); HANDLEPARSERCODE(parse_required_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn"));
parse_default_field(cell_cfg.dl_freq_hz, cellroot, "dl_freq", 0.0); // will be derived from DL EARFCN If not set parse_default_field(cell_cfg.dl_freq_hz, cellroot, "dl_freq", 0.0); // will be derived from DL EARFCN If not set
@ -1305,6 +1333,7 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
phy_cell_cfg.cell_id = cfg.cell_id; phy_cell_cfg.cell_id = cfg.cell_id;
phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
phy_cell_cfg.rf_port = cfg.rf_port; phy_cell_cfg.rf_port = cfg.rf_port;
phy_cell_cfg.gain_db = cfg.tx_gain;
phy_cell_cfg.num_ra_preambles = phy_cell_cfg.num_ra_preambles =
rrc_cfg_->sibs[1].sib2().rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.to_number(); rrc_cfg_->sibs[1].sib2().rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.to_number();

@ -368,7 +368,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
// Convert eNB Id // Convert eNB Id
std::size_t pos = {}; std::size_t pos = {};
try { try {
args->enb.enb_id = std::stoi(enb_id, &pos, 0); args->enb.enb_id = std::stoul(enb_id, &pos, 0);
} catch (...) { } catch (...) {
cout << "Error parsing enb.enb_id: " << enb_id << "." << endl; cout << "Error parsing enb.enb_id: " << enb_id << "." << endl;
exit(1); exit(1);

@ -643,7 +643,7 @@ void cc_worker::ue::metrics_read(phy_metrics_t* metrics_)
if (metrics_) { if (metrics_) {
*metrics_ = metrics; *metrics_ = metrics;
} }
bzero(&metrics, sizeof(phy_metrics_t)); metrics = {};
} }
void cc_worker::ue::metrics_dl(uint32_t mcs) void cc_worker::ue::metrics_dl(uint32_t mcs)

@ -27,7 +27,7 @@
#ifdef DEBUG_WRITE_FILE #ifdef DEBUG_WRITE_FILE
FILE* f; FILE* f;
static uint32_t num_slots = 0; static uint32_t num_slots = 0;
static uint32_t slots_to_dump = 10; static uint32_t slots_to_dump = 10;
#endif #endif
@ -293,9 +293,8 @@ bool slot_worker::work_dl()
// Releases synchronization lock and allow next worker to retrieve scheduling results // Releases synchronization lock and allow next worker to retrieve scheduling results
sync.release(); sync.release();
// Abort if the scheduling failed // Abort DL processing if the scheduling returned an invalid pointer
if (dl_sched_ptr == nullptr) { if (dl_sched_ptr == nullptr) {
logger.error("Error retrieving DL scheduling");
return false; return false;
} }

@ -147,6 +147,13 @@ int worker_pool::set_common_cfg(const phy_interface_rrc_nr::common_cfg_t& common
ssb_cfg.scaling = ssb_cfg.scaling =
srsran_convert_dB_to_amplitude(srsran_gnb_dl_get_maximum_signal_power_dBfs(common_cfg.carrier.nof_prb)); srsran_convert_dB_to_amplitude(srsran_gnb_dl_get_maximum_signal_power_dBfs(common_cfg.carrier.nof_prb));
// Print SSB configuration, helps debugging gNb and UE
if (logger.info.enabled()) {
std::array<char, 512> ssb_cfg_str = {};
srsran_ssb_cfg_to_str(&ssb_cfg, ssb_cfg_str.data(), (uint32_t)ssb_cfg_str.size());
logger.info("Setting SSB configuration %s", ssb_cfg_str.data());
}
// For each worker set configuration // For each worker set configuration
for (uint32_t i = 0; i < pool.get_nof_workers(); i++) { for (uint32_t i = 0; i < pool.get_nof_workers(); i++) {
// Reserve worker from pool // Reserve worker from pool

@ -704,7 +704,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list)
tb_count++; tb_count++;
} }
// Count transmission if at least one TB has succesfully added // Count transmission if at least one TB has successfully added
if (tb_count > 0) { if (tb_count > 0) {
n++; n++;
} }

@ -263,18 +263,34 @@ uint32_t allocate_mac_sdus(sched_interface::dl_sched_data_t* data,
uint32_t total_tbs, uint32_t total_tbs,
uint32_t tbidx) uint32_t tbidx)
{ {
uint32_t rem_tbs = total_tbs; uint32_t rem_tbs = total_tbs;
auto& pdu = data->pdu[tbidx];
uint32_t& nof_pdu_elems = data->nof_pdu_elems[tbidx];
// if we do not have enough bytes to fit MAC subheader, skip MAC SDU allocation // if we do not have enough bytes to fit MAC subheader, skip MAC SDU allocation
// NOTE: we do not account RLC header because some LCIDs (e.g. CCCH) do not need them // NOTE: we do not account RLC header because some LCIDs (e.g. CCCH) do not need them
uint32_t first_pdu_idx = nof_pdu_elems;
while (rem_tbs > MAC_MAX_HEADER_SIZE and data->nof_pdu_elems[tbidx] < sched_interface::MAX_RLC_PDU_LIST) { while (rem_tbs > MAC_MAX_HEADER_SIZE and data->nof_pdu_elems[tbidx] < sched_interface::MAX_RLC_PDU_LIST) {
uint32_t max_sdu_bytes = rem_tbs - get_mac_subheader_size(rem_tbs - MAC_MIN_HEADER_SIZE); uint32_t max_sdu_bytes = rem_tbs - get_mac_subheader_size(rem_tbs - MAC_MIN_HEADER_SIZE);
uint32_t alloc_sdu_bytes = lch_handler.alloc_rlc_pdu(&data->pdu[tbidx][data->nof_pdu_elems[tbidx]], max_sdu_bytes); uint32_t alloc_sdu_bytes = lch_handler.alloc_rlc_pdu(&pdu[nof_pdu_elems], max_sdu_bytes);
if (alloc_sdu_bytes == 0) { if (alloc_sdu_bytes == 0) {
break; break;
} }
rem_tbs -= get_mac_sdu_and_subheader_size(alloc_sdu_bytes); // account for MAC sub-header rem_tbs -= get_mac_sdu_and_subheader_size(alloc_sdu_bytes); // account for MAC sub-header
data->nof_pdu_elems[tbidx]++;
// In case the same LCID got reallocated (e.g. retx and newtx), merge with previous SDU.
// Otherwise, increment number of scheduled SDUs
uint32_t prev_same_lcid_idx = first_pdu_idx;
for (; prev_same_lcid_idx < nof_pdu_elems; ++prev_same_lcid_idx) {
if (pdu[prev_same_lcid_idx].lcid == pdu[nof_pdu_elems].lcid) {
pdu[prev_same_lcid_idx].nbytes += pdu[nof_pdu_elems].nbytes;
pdu[nof_pdu_elems].nbytes = 0;
break;
}
}
if (prev_same_lcid_idx == nof_pdu_elems) {
nof_pdu_elems++;
}
} }
return total_tbs - rem_tbs; return total_tbs - rem_tbs;

@ -277,10 +277,11 @@ void mac_controller::handle_intraenb_ho_cmd(const asn1::rrc::rrc_conn_recfg_r8_i
const srsran::rrc_ue_capabilities_t& uecaps) const srsran::rrc_ue_capabilities_t& uecaps)
{ {
next_sched_ue_cfg = current_sched_ue_cfg; next_sched_ue_cfg = current_sched_ue_cfg;
next_sched_ue_cfg.supported_cc_list.resize(1);
next_sched_ue_cfg.supported_cc_list[0].active = true;
next_sched_ue_cfg.supported_cc_list[0].enb_cc_idx = next_sched_ue_cfg.supported_cc_list[0].enb_cc_idx =
cell_common_list.get_pci(conn_recfg.mob_ctrl_info.target_pci)->enb_cc_idx; cell_common_list.get_pci(conn_recfg.mob_ctrl_info.target_pci)->enb_cc_idx;
for (uint32_t i = 0; i < next_sched_ue_cfg.supported_cc_list.size(); ++i) {
next_sched_ue_cfg.supported_cc_list[0].active = true;
}
ue_cfg_apply_conn_reconf(next_sched_ue_cfg, conn_recfg, *rrc_cfg); ue_cfg_apply_conn_reconf(next_sched_ue_cfg, conn_recfg, *rrc_cfg);
ue_cfg_apply_capabilities(next_sched_ue_cfg, *rrc_cfg, uecaps); ue_cfg_apply_capabilities(next_sched_ue_cfg, *rrc_cfg, uecaps);
ue_cfg_apply_reconf_complete_updates(next_sched_ue_cfg, conn_recfg, ue_cell_list); ue_cfg_apply_reconf_complete_updates(next_sched_ue_cfg, conn_recfg, ue_cell_list);

@ -325,8 +325,7 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci,
capitem.ue_category = 4; capitem.ue_category = 4;
capitem.pdcp_params.max_num_rohc_context_sessions_present = true; capitem.pdcp_params.max_num_rohc_context_sessions_present = true;
capitem.pdcp_params.max_num_rohc_context_sessions = asn1::rrc::pdcp_params_s::max_num_rohc_context_sessions_e_::cs2; capitem.pdcp_params.max_num_rohc_context_sessions = asn1::rrc::pdcp_params_s::max_num_rohc_context_sessions_e_::cs2;
bzero(&capitem.pdcp_params.supported_rohc_profiles, capitem.pdcp_params.supported_rohc_profiles = {};
sizeof(asn1::rrc::rohc_profile_support_list_r15_s)); // TODO: why is it r15?
capitem.phy_layer_params.ue_specific_ref_sigs_supported = false; capitem.phy_layer_params.ue_specific_ref_sigs_supported = false;
capitem.phy_layer_params.ue_tx_ant_sel_supported = false; capitem.phy_layer_params.ue_tx_ant_sel_supported = false;
capitem.rf_params.supported_band_list_eutra.resize(1); capitem.rf_params.supported_band_list_eutra.resize(1);
@ -443,9 +442,9 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(rrc::ho_prep_result
} }
// Check if any E-RAB that was not admitted. Cancel Handover, in such case. // Check if any E-RAB that was not admitted. Cancel Handover, in such case.
if (msg.protocol_ies.erab_to_release_list_ho_cmd_present) { if (msg->erab_to_release_list_ho_cmd_present) {
get_logger().warning("E-RAB id=%d was not admitted in target eNB. Cancelling handover...", get_logger().warning("E-RAB id=%d was not admitted in target eNB. Cancelling handover...",
msg.protocol_ies.erab_to_release_list_ho_cmd.value[0].value.erab_item().erab_id); msg->erab_to_release_list_ho_cmd.value[0]->erab_item().erab_id);
asn1::s1ap::cause_c cause; asn1::s1ap::cause_c cause;
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell; cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell;
trigger(ho_cancel_ev{cause}); trigger(ho_cancel_ev{cause});
@ -631,11 +630,11 @@ rrc::ue::rrc_mobility::s1_source_ho_st::start_enb_status_transfer(const asn1::s1
} }
// Setup GTPU forwarding tunnel // Setup GTPU forwarding tunnel
if (s1ap_ho_cmd.protocol_ies.erab_subjectto_data_forwarding_list_present) { if (s1ap_ho_cmd->erab_subjectto_data_forwarding_list_present) {
const auto& fwd_erab_list = s1ap_ho_cmd.protocol_ies.erab_subjectto_data_forwarding_list.value; const auto& fwd_erab_list = s1ap_ho_cmd->erab_subjectto_data_forwarding_list.value;
const auto& erab_list = rrc_ue->bearer_list.get_erabs(); const auto& erab_list = rrc_ue->bearer_list.get_erabs();
for (const auto& e : fwd_erab_list) { for (const auto& e : fwd_erab_list) {
const auto& fwd_erab = e.value.erab_data_forwarding_item(); const auto& fwd_erab = e->erab_data_forwarding_item();
auto it = erab_list.find(fwd_erab.erab_id); auto it = erab_list.find(fwd_erab.erab_id);
if (it == erab_list.end()) { if (it == erab_list.end()) {
Warning("E-RAB id=%d subject to forwarding not found\n", fwd_erab.erab_id); Warning("E-RAB id=%d subject to forwarding not found\n", fwd_erab.erab_id);
@ -819,7 +818,7 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
rrc_ue->ue_security_cfg.get_security_algorithm_cfg(); rrc_ue->ue_security_cfg.get_security_algorithm_cfg();
recfg_r8.security_cfg_ho.handov_type.intra_lte().key_change_ind = false; recfg_r8.security_cfg_ho.handov_type.intra_lte().key_change_ind = false;
recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count = recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count =
ho_req.ho_req_msg->protocol_ies.security_context.value.next_hop_chaining_count; (*ho_req.ho_req_msg)->security_context.value.next_hop_chaining_count;
/* Prepare Handover Command to be sent via S1AP */ /* Prepare Handover Command to be sent via S1AP */
srsran::unique_byte_buffer_t ho_cmd_pdu = srsran::make_byte_buffer(); srsran::unique_byte_buffer_t ho_cmd_pdu = srsran::make_byte_buffer();
@ -872,16 +871,16 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
// Establish GTPU Forwarding Paths // Establish GTPU Forwarding Paths
if (ho_req.transparent_container->erab_info_list_present) { if (ho_req.transparent_container->erab_info_list_present) {
const auto& lst = ho_req.transparent_container->erab_info_list; const auto& lst = ho_req.transparent_container->erab_info_list;
const auto* it = std::find_if( const auto* it =
lst.begin(), std::find_if(lst.begin(),
lst.end(), lst.end(),
[&erab](const asn1::s1ap::protocol_ie_single_container_s<asn1::s1ap::erab_info_list_ies_o>& fwd_erab) { [&erab](const asn1::protocol_ie_single_container_s<asn1::s1ap::erab_info_list_ies_o>& fwd_erab) {
return fwd_erab.value.erab_info_list_item().erab_id == erab.second.id; return fwd_erab->erab_info_list_item().erab_id == erab.second.id;
}); });
if (it == lst.end()) { if (it == lst.end()) {
continue; continue;
} }
const auto& fwd_erab = it->value.erab_info_list_item(); const auto& fwd_erab = (*it)->erab_info_list_item();
if (fwd_erab.dl_forwarding_present and if (fwd_erab.dl_forwarding_present and
fwd_erab.dl_forwarding.value == asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed) { fwd_erab.dl_forwarding.value == asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed) {
@ -944,8 +943,8 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s&
const cell_cfg_t& target_cell_cfg = target_cell->cell_common->cell_cfg; const cell_cfg_t& target_cell_cfg = target_cell->cell_common->cell_cfg;
// Establish ERABs/DRBs // Establish ERABs/DRBs
for (const auto& erab_item : ho_req_msg.protocol_ies.erab_to_be_setup_list_ho_req.value) { for (const auto& erab_item : ho_req_msg->erab_to_be_setup_list_ho_req.value) {
const auto& erab = erab_item.value.erab_to_be_setup_item_ho_req(); const auto& erab = erab_item->erab_to_be_setup_item_ho_req();
if (erab.ext) { if (erab.ext) {
get_logger().warning("Not handling E-RABToBeSetupList extensions"); get_logger().warning("Not handling E-RABToBeSetupList extensions");
} }
@ -981,13 +980,13 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s&
// Regenerate AS Keys // Regenerate AS Keys
// See TS 33.401, Sec. 7.2.8.4.3 // See TS 33.401, Sec. 7.2.8.4.3
if (not rrc_ue->ue_security_cfg.set_security_capabilities(ho_req_msg.protocol_ies.ue_security_cap.value)) { if (not rrc_ue->ue_security_cfg.set_security_capabilities(ho_req_msg->ue_security_cap.value)) {
cause.set_radio_network().value = cause.set_radio_network().value =
asn1::s1ap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported; asn1::s1ap::cause_radio_network_opts::encryption_and_or_integrity_protection_algorithms_not_supported;
return false; return false;
} }
rrc_ue->ue_security_cfg.set_security_key(ho_req_msg.protocol_ies.security_context.value.next_hop_param); rrc_ue->ue_security_cfg.set_security_key(ho_req_msg->security_context.value.next_hop_param);
rrc_ue->ue_security_cfg.set_ncc(ho_req_msg.protocol_ies.security_context.value.next_hop_chaining_count); rrc_ue->ue_security_cfg.set_ncc(ho_req_msg->security_context.value.next_hop_chaining_count);
rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn); rrc_ue->ue_security_cfg.regenerate_keys_handover(target_cell_cfg.pci, target_cell_cfg.dl_earfcn);
// Save UE Capabilities // Save UE Capabilities
@ -1047,7 +1046,7 @@ void rrc::ue::rrc_mobility::handle_status_transfer(s1_target_ho_st& s, const sta
// Set DRBs SNs // Set DRBs SNs
for (const auto& erab : erabs) { for (const auto& erab : erabs) {
const auto& erab_item = erab.value.bearers_subject_to_status_transfer_item(); const auto& erab_item = erab->bearers_subject_to_status_transfer_item();
auto erab_it = rrc_ue->bearer_list.get_erabs().find(erab_item.erab_id); auto erab_it = rrc_ue->bearer_list.get_erabs().find(erab_item.erab_id);
if (erab_it == rrc_ue->bearer_list.get_erabs().end()) { if (erab_it == rrc_ue->bearer_list.get_erabs().end()) {
logger.warning("The E-RAB Id=%d is not recognized", erab_item.erab_id); logger.warning("The E-RAB Id=%d is not recognized", erab_item.erab_id);

@ -1145,14 +1145,14 @@ void rrc::ue::send_connection_release()
*/ */
void rrc::ue::handle_ue_init_ctxt_setup_req(const asn1::s1ap::init_context_setup_request_s& msg) void rrc::ue::handle_ue_init_ctxt_setup_req(const asn1::s1ap::init_context_setup_request_s& msg)
{ {
set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); set_bitrates(msg->ueaggregate_maximum_bitrate.value);
ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); ue_security_cfg.set_security_capabilities(msg->ue_security_cap.value);
ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); ue_security_cfg.set_security_key(msg->security_key.value);
// CSFB // CSFB
if (msg.protocol_ies.cs_fallback_ind_present) { if (msg->cs_fallback_ind_present) {
if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required or if (msg->cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required or
msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { msg->cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) {
is_csfb = true; is_csfb = true;
} }
} }
@ -1163,25 +1163,25 @@ void rrc::ue::handle_ue_init_ctxt_setup_req(const asn1::s1ap::init_context_setup
bool rrc::ue::handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg) bool rrc::ue::handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg)
{ {
if (msg.protocol_ies.cs_fallback_ind_present) { if (msg->cs_fallback_ind_present) {
if (msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required || if (msg->cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_required ||
msg.protocol_ies.cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) { msg->cs_fallback_ind.value.value == asn1::s1ap::cs_fallback_ind_opts::cs_fallback_high_prio) {
/* Remember that we are in a CSFB right now */ /* Remember that we are in a CSFB right now */
is_csfb = true; is_csfb = true;
} }
} }
// UEAggregateMaximumBitrate // UEAggregateMaximumBitrate
if (msg.protocol_ies.ueaggregate_maximum_bitrate_present) { if (msg->ueaggregate_maximum_bitrate_present) {
set_bitrates(msg.protocol_ies.ueaggregate_maximum_bitrate.value); set_bitrates(msg->ueaggregate_maximum_bitrate.value);
} }
if (msg.protocol_ies.ue_security_cap_present) { if (msg->ue_security_cap_present) {
ue_security_cfg.set_security_capabilities(msg.protocol_ies.ue_security_cap.value); ue_security_cfg.set_security_capabilities(msg->ue_security_cap.value);
} }
if (msg.protocol_ies.security_key_present) { if (msg->security_key_present) {
ue_security_cfg.set_security_key(msg.protocol_ies.security_key.value); ue_security_cfg.set_security_key(msg->security_key.value);
send_security_mode_command(); send_security_mode_command();
} }

@ -117,7 +117,7 @@ void fill_erab_failed_setup_list(OutList& output_list, const s1ap::erab_item_lis
output_list.resize(input_list.size()); output_list.resize(input_list.size());
for (size_t i = 0; i < input_list.size(); ++i) { for (size_t i = 0; i < input_list.size(); ++i) {
output_list[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); output_list[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
output_list[i].value.erab_item() = input_list[i]; output_list[i]->erab_item() = input_list[i];
} }
} }
@ -158,7 +158,7 @@ srsran::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const ho_prep_fail_s& msg
{ {
ue_ptr->ts1_reloc_prep.stop(); ue_ptr->ts1_reloc_prep.stop();
std::string cause = s1ap_ptr->get_cause(msg.protocol_ies.cause.value); std::string cause = s1ap_ptr->get_cause(msg->cause.value);
procError("HO preparation Failure. Cause: %s", cause.c_str()); procError("HO preparation Failure. Cause: %s", cause.c_str());
srsran::console("HO preparation Failure. Cause: %s\n", cause.c_str()); srsran::console("HO preparation Failure. Cause: %s\n", cause.c_str());
@ -176,16 +176,16 @@ srsran::proc_outcome_t s1ap::ue::ho_prep_proc_t::react(const asn1::s1ap::ho_cmd_
ue_ptr->ts1_reloc_overall.run(); ue_ptr->ts1_reloc_overall.run();
// Check for unsupported S1AP fields // Check for unsupported S1AP fields
if (msg.ext or msg.protocol_ies.target_to_source_transparent_container_secondary_present or if (msg.ext or msg->target_to_source_transparent_container_secondary_present or
msg.protocol_ies.handov_type.value.value != handov_type_opts::intralte or msg->handov_type.value.value != handov_type_opts::intralte or msg->crit_diagnostics_present or
msg.protocol_ies.crit_diagnostics_present or msg.protocol_ies.nas_security_paramsfrom_e_utran_present) { msg->nas_security_paramsfrom_e_utran_present) {
procWarning("Not handling HandoverCommand extensions and non-intraLTE params"); procWarning("Not handling HandoverCommand extensions and non-intraLTE params");
} }
// In case of intra-system Handover, Target to Source Transparent Container IE shall be encoded as // In case of intra-system Handover, Target to Source Transparent Container IE shall be encoded as
// Target eNB to Source eNB Transparent Container IE // Target eNB to Source eNB Transparent Container IE
asn1::cbit_ref bref(msg.protocol_ies.target_to_source_transparent_container.value.data(), asn1::cbit_ref bref(msg->target_to_source_transparent_container.value.data(),
msg.protocol_ies.target_to_source_transparent_container.value.size()); msg->target_to_source_transparent_container.value.size());
asn1::s1ap::targetenb_to_sourceenb_transparent_container_s container; asn1::s1ap::targetenb_to_sourceenb_transparent_container_s container;
if (container.unpack(bref) != asn1::SRSASN_SUCCESS) { if (container.unpack(bref) != asn1::SRSASN_SUCCESS) {
procError("Failed to decode TargeteNBToSourceeNBTransparentContainer"); procError("Failed to decode TargeteNBToSourceeNBTransparentContainer");
@ -537,25 +537,25 @@ bool s1ap::setup_s1()
s1ap_pdu_c pdu; s1ap_pdu_c pdu;
pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_S1_SETUP); pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_S1_SETUP);
s1_setup_request_ies_container& container = pdu.init_msg().value.s1_setup_request().protocol_ies; s1_setup_request_s& container = pdu.init_msg().value.s1_setup_request();
container.global_enb_id.value.plm_nid[0] = ((uint8_t*)&plmn)[1]; container->global_enb_id.value.plm_nid[0] = ((uint8_t*)&plmn)[1];
container.global_enb_id.value.plm_nid[1] = ((uint8_t*)&plmn)[2]; container->global_enb_id.value.plm_nid[1] = ((uint8_t*)&plmn)[2];
container.global_enb_id.value.plm_nid[2] = ((uint8_t*)&plmn)[3]; container->global_enb_id.value.plm_nid[2] = ((uint8_t*)&plmn)[3];
container.global_enb_id.value.enb_id.set_macro_enb_id().from_number(args.enb_id); container->global_enb_id.value.enb_id.set_macro_enb_id().from_number(args.enb_id);
container.enbname_present = true; container->enbname_present = true;
container.enbname.value.from_string(args.enb_name); container->enbname.value.from_string(args.enb_name);
container.supported_tas.value.resize(1); container->supported_tas.value.resize(1);
tmp16 = htons(args.tac); tmp16 = htons(args.tac);
memcpy(container.supported_tas.value[0].tac.data(), (uint8_t*)&tmp16, 2); memcpy(container->supported_tas.value[0].tac.data(), (uint8_t*)&tmp16, 2);
container.supported_tas.value[0].broadcast_plmns.resize(1); container->supported_tas.value[0].broadcast_plmns.resize(1);
container.supported_tas.value[0].broadcast_plmns[0][0] = ((uint8_t*)&plmn)[1]; container->supported_tas.value[0].broadcast_plmns[0][0] = ((uint8_t*)&plmn)[1];
container.supported_tas.value[0].broadcast_plmns[0][1] = ((uint8_t*)&plmn)[2]; container->supported_tas.value[0].broadcast_plmns[0][1] = ((uint8_t*)&plmn)[2];
container.supported_tas.value[0].broadcast_plmns[0][2] = ((uint8_t*)&plmn)[3]; container->supported_tas.value[0].broadcast_plmns[0][2] = ((uint8_t*)&plmn)[3];
container.default_paging_drx.value.value = asn1::s1ap::paging_drx_opts::v128; // Todo: add to args, config file container->default_paging_drx.value.value = asn1::s1ap::paging_drx_opts::v128; // Todo: add to args, config file
return sctp_send_s1ap_pdu(pdu, 0, "s1SetupRequest"); return sctp_send_s1ap_pdu(pdu, 0, "s1SetupRequest");
} }
@ -741,16 +741,15 @@ bool s1ap::handle_dlnastransport(const dl_nas_transport_s& msg)
if (msg.ext) { if (msg.ext) {
logger.warning("Not handling S1AP message extension"); logger.warning("Not handling S1AP message extension");
} }
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
if (msg.protocol_ies.ho_restrict_list_present) { if (msg->ho_restrict_list_present) {
logger.warning("Not handling HandoverRestrictionList"); logger.warning("Not handling HandoverRestrictionList");
} }
if (msg.protocol_ies.subscriber_profile_idfor_rfp_present) { if (msg->subscriber_profile_idfor_rfp_present) {
logger.warning("Not handling SubscriberProfileIDforRFP"); logger.warning("Not handling SubscriberProfileIDforRFP");
} }
@ -759,31 +758,29 @@ bool s1ap::handle_dlnastransport(const dl_nas_transport_s& msg)
logger.error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread()."); logger.error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread().");
return false; return false;
} }
memcpy(pdu->msg, msg.protocol_ies.nas_pdu.value.data(), msg.protocol_ies.nas_pdu.value.size()); memcpy(pdu->msg, msg->nas_pdu.value.data(), msg->nas_pdu.value.size());
pdu->N_bytes = msg.protocol_ies.nas_pdu.value.size(); pdu->N_bytes = msg->nas_pdu.value.size();
rrc->write_dl_info(u->ctxt.rnti, std::move(pdu)); rrc->write_dl_info(u->ctxt.rnti, std::move(pdu));
return true; return true;
} }
bool s1ap::handle_initialctxtsetuprequest(const init_context_setup_request_s& msg) bool s1ap::handle_initialctxtsetuprequest(const init_context_setup_request_s& msg)
{ {
const auto& prot_ies = msg.protocol_ies;
WarnUnsupportFeature(msg.ext, "message extension"); WarnUnsupportFeature(msg.ext, "message extension");
WarnUnsupportFeature(prot_ies.add_cs_fallback_ind_present, "AdditionalCSFallbackIndicator"); WarnUnsupportFeature(msg->add_cs_fallback_ind_present, "AdditionalCSFallbackIndicator");
WarnUnsupportFeature(prot_ies.csg_membership_status_present, "CSGMembershipStatus"); WarnUnsupportFeature(msg->csg_membership_status_present, "CSGMembershipStatus");
WarnUnsupportFeature(prot_ies.gummei_id_present, "GUMMEI_ID"); WarnUnsupportFeature(msg->gummei_id_present, "GUMMEI_ID");
WarnUnsupportFeature(prot_ies.ho_restrict_list_present, "HandoverRestrictionList"); WarnUnsupportFeature(msg->ho_restrict_list_present, "HandoverRestrictionList");
WarnUnsupportFeature(prot_ies.management_based_mdt_allowed_present, "ManagementBasedMDTAllowed"); WarnUnsupportFeature(msg->management_based_mdt_allowed_present, "ManagementBasedMDTAllowed");
WarnUnsupportFeature(prot_ies.management_based_mdtplmn_list_present, "ManagementBasedMDTPLMNList"); WarnUnsupportFeature(msg->management_based_mdtplmn_list_present, "ManagementBasedMDTPLMNList");
WarnUnsupportFeature(prot_ies.mme_ue_s1ap_id_minus2_present, "MME_UE_S1AP_ID_2"); WarnUnsupportFeature(msg->mme_ue_s1ap_id_minus2_present, "MME_UE_S1AP_ID_2");
WarnUnsupportFeature(prot_ies.registered_lai_present, "RegisteredLAI"); WarnUnsupportFeature(msg->registered_lai_present, "RegisteredLAI");
WarnUnsupportFeature(prot_ies.srvcc_operation_possible_present, "SRVCCOperationPossible"); WarnUnsupportFeature(msg->srvcc_operation_possible_present, "SRVCCOperationPossible");
WarnUnsupportFeature(prot_ies.subscriber_profile_idfor_rfp_present, "SubscriberProfileIDforRFP"); WarnUnsupportFeature(msg->subscriber_profile_idfor_rfp_present, "SubscriberProfileIDforRFP");
WarnUnsupportFeature(prot_ies.trace_activation_present, "TraceActivation"); WarnUnsupportFeature(msg->trace_activation_present, "TraceActivation");
WarnUnsupportFeature(prot_ies.ue_radio_cap_present, "UERadioCapability"); WarnUnsupportFeature(msg->ue_radio_cap_present, "UERadioCapability");
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
@ -796,10 +793,10 @@ bool s1ap::handle_initialctxtsetuprequest(const init_context_setup_request_s& ms
// Update E-RABs // Update E-RABs
erab_id_list updated_erabs; erab_id_list updated_erabs;
erab_item_list failed_cfg_erabs; erab_item_list failed_cfg_erabs;
add_repeated_erab_ids(prot_ies.erab_to_be_setup_list_ctxt_su_req.value, failed_cfg_erabs); add_repeated_erab_ids(msg->erab_to_be_setup_list_ctxt_su_req.value, failed_cfg_erabs);
for (const auto& item : msg.protocol_ies.erab_to_be_setup_list_ctxt_su_req.value) { for (const auto& item : msg->erab_to_be_setup_list_ctxt_su_req.value) {
const auto& erab = item.value.erab_to_be_setup_item_ctxt_su_req(); const auto& erab = item->erab_to_be_setup_item_ctxt_su_req();
if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) { if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) {
// E-RAB is duplicate // E-RAB is duplicate
continue; continue;
@ -832,9 +829,9 @@ bool s1ap::handle_initialctxtsetuprequest(const init_context_setup_request_s& ms
} }
/* Ideally the check below would be "if (users[rnti].is_csfb)" */ /* Ideally the check below would be "if (users[rnti].is_csfb)" */
if (msg.protocol_ies.cs_fallback_ind_present) { if (msg->cs_fallback_ind_present) {
if (msg.protocol_ies.cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_required || if (msg->cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_required ||
msg.protocol_ies.cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_high_prio) { msg->cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_high_prio) {
// Send RRC Release (cs-fallback-triggered) to MME // Send RRC Release (cs-fallback-triggered) to MME
cause_c cause; cause_c cause;
cause.set_radio_network().value = cause_radio_network_opts::cs_fallback_triggered; cause.set_radio_network().value = cause_radio_network_opts::cs_fallback_triggered;
@ -854,8 +851,8 @@ bool s1ap::handle_paging(const asn1::s1ap::paging_s& msg)
{ {
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
uint32_t ueid = msg.protocol_ies.ue_id_idx_value.value.to_number(); uint32_t ueid = msg->ue_id_idx_value.value.to_number();
rrc->add_paging_id(ueid, msg.protocol_ies.ue_paging_id.value); rrc->add_paging_id(ueid, msg->ue_paging_id.value);
return true; return true;
} }
@ -863,22 +860,21 @@ bool s1ap::handle_erabsetuprequest(const erab_setup_request_s& msg)
{ {
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
if (msg.protocol_ies.ueaggregate_maximum_bitrate_present) { if (msg->ueaggregate_maximum_bitrate_present) {
rrc->set_aggregate_max_bitrate(u->ctxt.rnti, msg.protocol_ies.ueaggregate_maximum_bitrate.value); rrc->set_aggregate_max_bitrate(u->ctxt.rnti, msg->ueaggregate_maximum_bitrate.value);
} }
erab_id_list updated_erabs; erab_id_list updated_erabs;
erab_item_list failed_cfg_erabs; erab_item_list failed_cfg_erabs;
add_repeated_erab_ids(msg.protocol_ies.erab_to_be_setup_list_bearer_su_req.value, failed_cfg_erabs); add_repeated_erab_ids(msg->erab_to_be_setup_list_bearer_su_req.value, failed_cfg_erabs);
for (const auto& item : msg.protocol_ies.erab_to_be_setup_list_bearer_su_req.value) { for (const auto& item : msg->erab_to_be_setup_list_bearer_su_req.value) {
const auto& erab = item.value.erab_to_be_setup_item_bearer_su_req(); const auto& erab = item->erab_to_be_setup_item_bearer_su_req();
if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) { if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) {
// E-RAB is duplicate // E-RAB is duplicate
continue; continue;
@ -923,22 +919,21 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg)
{ {
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
if (msg.protocol_ies.ueaggregate_maximum_bitrate_present) { if (msg->ueaggregate_maximum_bitrate_present) {
rrc->set_aggregate_max_bitrate(u->ctxt.rnti, msg.protocol_ies.ueaggregate_maximum_bitrate.value); rrc->set_aggregate_max_bitrate(u->ctxt.rnti, msg->ueaggregate_maximum_bitrate.value);
} }
erab_id_list updated_erabs; erab_id_list updated_erabs;
erab_item_list failed_cfg_erabs; erab_item_list failed_cfg_erabs;
add_repeated_erab_ids(msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value, failed_cfg_erabs); add_repeated_erab_ids(msg->erab_to_be_modified_list_bearer_mod_req.value, failed_cfg_erabs);
for (const auto& item : msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value) { for (const auto& item : msg->erab_to_be_modified_list_bearer_mod_req.value) {
const auto& erab = item.value.erab_to_be_modified_item_bearer_mod_req(); const auto& erab = item->erab_to_be_modified_item_bearer_mod_req();
if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) { if (contains_erab_id(failed_cfg_erabs, erab.erab_id)) {
// E-RAB is duplicate // E-RAB is duplicate
continue; continue;
@ -978,8 +973,7 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg)
{ {
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
@ -993,8 +987,8 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg)
return e.erab_id == erab_id; return e.erab_id == erab_id;
})); }));
}; };
for (const auto& item : msg.protocol_ies.erab_to_be_released_list.value) { for (const auto& item : msg->erab_to_be_released_list.value) {
const auto& erab = item.value.erab_item(); const auto& erab = item->erab_item();
if (is_repeated_erab_id(erab.erab_id)) { if (is_repeated_erab_id(erab.erab_id)) {
// TS 36.413, 8.2.3.3 - ignore the duplication of E-RAB ID IEs // TS 36.413, 8.2.3.3 - ignore the duplication of E-RAB ID IEs
@ -1012,7 +1006,7 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg)
// Notify RRC of E-RAB update. (RRC reconf message is going to be sent. // Notify RRC of E-RAB update. (RRC reconf message is going to be sent.
if (not updated_erabs.empty()) { if (not updated_erabs.empty()) {
rrc->notify_ue_erab_updates(u->ctxt.rnti, msg.protocol_ies.nas_pdu.value); rrc->notify_ue_erab_updates(u->ctxt.rnti, msg->nas_pdu.value);
} }
// Send E-RAB release response back to the MME // Send E-RAB release response back to the MME
@ -1028,13 +1022,12 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg)
bool s1ap::handle_uecontextmodifyrequest(const ue_context_mod_request_s& msg) bool s1ap::handle_uecontextmodifyrequest(const ue_context_mod_request_s& msg)
{ {
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
WarnUnsupportFeature(msg.protocol_ies.add_cs_fallback_ind_present, "AdditionalCSFallbackIndicator"); WarnUnsupportFeature(msg->add_cs_fallback_ind_present, "AdditionalCSFallbackIndicator");
WarnUnsupportFeature(msg.protocol_ies.csg_membership_status_present, "CSGMembershipStatus"); WarnUnsupportFeature(msg->csg_membership_status_present, "CSGMembershipStatus");
WarnUnsupportFeature(msg.protocol_ies.registered_lai_present, "RegisteredLAI"); WarnUnsupportFeature(msg->registered_lai_present, "RegisteredLAI");
WarnUnsupportFeature(msg.protocol_ies.subscriber_profile_idfor_rfp_present, "SubscriberProfileIDforRFP"); WarnUnsupportFeature(msg->subscriber_profile_idfor_rfp_present, "SubscriberProfileIDforRFP");
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
@ -1050,9 +1043,9 @@ bool s1ap::handle_uecontextmodifyrequest(const ue_context_mod_request_s& msg)
u->send_uectxtmodifyresp(); u->send_uectxtmodifyresp();
/* Ideally the check below would be "if (users[rnti].is_csfb)" */ /* Ideally the check below would be "if (users[rnti].is_csfb)" */
if (msg.protocol_ies.cs_fallback_ind_present) { if (msg->cs_fallback_ind_present) {
if (msg.protocol_ies.cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_required || if (msg->cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_required ||
msg.protocol_ies.cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_high_prio) { msg->cs_fallback_ind.value.value == cs_fallback_ind_opts::cs_fallback_high_prio) {
// Send RRC Release (cs-fallback-triggered) to MME // Send RRC Release (cs-fallback-triggered) to MME
cause_c cause; cause_c cause;
cause.set_radio_network().value = cause_radio_network_opts::cs_fallback_triggered; cause.set_radio_network().value = cause_radio_network_opts::cs_fallback_triggered;
@ -1069,8 +1062,8 @@ bool s1ap::handle_uectxtreleasecommand(const ue_context_release_cmd_s& msg)
WarnUnsupportFeature(msg.ext, "S1AP message extension"); WarnUnsupportFeature(msg.ext, "S1AP message extension");
ue* u = nullptr; ue* u = nullptr;
if (msg.protocol_ies.ue_s1ap_ids.value.type().value == ue_s1ap_ids_c::types_opts::ue_s1ap_id_pair) { if (msg->ue_s1ap_ids.value.type().value == ue_s1ap_ids_c::types_opts::ue_s1ap_id_pair) {
const auto& idpair = msg.protocol_ies.ue_s1ap_ids.value.ue_s1ap_id_pair(); const auto& idpair = msg->ue_s1ap_ids.value.ue_s1ap_id_pair();
if (idpair.ext) { if (idpair.ext) {
logger.warning("Not handling S1AP message extension"); logger.warning("Not handling S1AP message extension");
@ -1083,7 +1076,7 @@ bool s1ap::handle_uectxtreleasecommand(const ue_context_release_cmd_s& msg)
return false; return false;
} }
} else { } else {
uint32_t mme_ue_id = msg.protocol_ies.ue_s1ap_ids.value.mme_ue_s1ap_id(); uint32_t mme_ue_id = msg->ue_s1ap_ids.value.mme_ue_s1ap_id();
u = users.find_ue_mmeid(mme_ue_id); u = users.find_ue_mmeid(mme_ue_id);
if (u == nullptr) { if (u == nullptr) {
logger.warning("UE for mme_ue_s1ap_id:%d not found - discarding message", mme_ue_id); logger.warning("UE for mme_ue_s1ap_id:%d not found - discarding message", mme_ue_id);
@ -1109,7 +1102,7 @@ bool s1ap::handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg)
return false; return false;
} }
std::string cause = get_cause(msg.protocol_ies.cause.value); std::string cause = get_cause(msg->cause.value);
logger.error("S1 Setup Failure. Cause: %s", cause.c_str()); logger.error("S1 Setup Failure. Cause: %s", cause.c_str());
srsran::console("S1 Setup Failure. Cause: %s\n", cause.c_str()); srsran::console("S1 Setup Failure. Cause: %s\n", cause.c_str());
return true; return true;
@ -1117,8 +1110,7 @@ bool s1ap::handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg)
bool s1ap::handle_handover_preparation_failure(const ho_prep_fail_s& msg) bool s1ap::handle_handover_preparation_failure(const ho_prep_fail_s& msg)
{ {
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
@ -1136,8 +1128,7 @@ bool s1ap::handle_handover_preparation_failure(const ho_prep_fail_s& msg)
bool s1ap::handle_handover_command(const asn1::s1ap::ho_cmd_s& msg) bool s1ap::handle_handover_command(const asn1::s1ap::ho_cmd_s& msg)
{ {
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
@ -1159,15 +1150,15 @@ bool s1ap::handle_handover_command(const asn1::s1ap::ho_cmd_s& msg)
bool s1ap::handle_handover_request(const asn1::s1ap::ho_request_s& msg) bool s1ap::handle_handover_request(const asn1::s1ap::ho_request_s& msg)
{ {
uint16_t rnti = SRSRAN_INVALID_RNTI; uint16_t rnti = SRSRAN_INVALID_RNTI;
uint32_t mme_ue_s1ap_id = msg.protocol_ies.mme_ue_s1ap_id.value.value; uint32_t mme_ue_s1ap_id = msg->mme_ue_s1ap_id.value.value;
asn1::s1ap::cause_c cause; asn1::s1ap::cause_c cause;
cause.set_misc().value = cause_misc_opts::unspecified; cause.set_misc().value = cause_misc_opts::unspecified;
if (msg.ext or msg.protocol_ies.ho_restrict_list_present) { if (msg.ext or msg->ho_restrict_list_present) {
logger.warning("Not handling S1AP Handover Request extensions or Handover Restriction List"); logger.warning("Not handling S1AP Handover Request extensions or Handover Restriction List");
} }
if (msg.protocol_ies.handov_type.value.value != handov_type_opts::intralte) { if (msg->handov_type.value.value != handov_type_opts::intralte) {
logger.error("Not handling S1AP non-intra LTE handovers"); logger.error("Not handling S1AP non-intra LTE handovers");
cause.set_radio_network().value = cause_radio_network_opts::interrat_redirection; cause.set_radio_network().value = cause_radio_network_opts::interrat_redirection;
send_ho_failure(mme_ue_s1ap_id, cause); send_ho_failure(mme_ue_s1ap_id, cause);
@ -1175,9 +1166,9 @@ bool s1ap::handle_handover_request(const asn1::s1ap::ho_request_s& msg)
} }
// Confirm the UE does not exist in TeNB // Confirm the UE does not exist in TeNB
if (users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value) != nullptr) { if (users.find_ue_mmeid(msg->mme_ue_s1ap_id.value.value) != nullptr) {
logger.error("The provided MME_UE_S1AP_ID=%" PRIu64 " is already connected to the cell", logger.error("The provided MME_UE_S1AP_ID=%" PRIu64 " is already connected to the cell",
msg.protocol_ies.mme_ue_s1ap_id.value.value); msg->mme_ue_s1ap_id.value.value);
cause.set_radio_network().value = cause_radio_network_opts::unknown_mme_ue_s1ap_id; cause.set_radio_network().value = cause_radio_network_opts::unknown_mme_ue_s1ap_id;
send_ho_failure(mme_ue_s1ap_id, cause); send_ho_failure(mme_ue_s1ap_id, cause);
return false; return false;
@ -1185,13 +1176,13 @@ bool s1ap::handle_handover_request(const asn1::s1ap::ho_request_s& msg)
// Create user ctxt object and associated MME context // Create user ctxt object and associated MME context
std::unique_ptr<ue> ue_ptr{new ue{this}}; std::unique_ptr<ue> ue_ptr{new ue{this}};
ue_ptr->ctxt.mme_ue_s1ap_id = msg.protocol_ies.mme_ue_s1ap_id.value.value; ue_ptr->ctxt.mme_ue_s1ap_id = msg->mme_ue_s1ap_id.value.value;
srsran_assert(users.add_user(std::move(ue_ptr)) != nullptr, "Unexpected failure to create S1AP UE"); srsran_assert(users.add_user(std::move(ue_ptr)) != nullptr, "Unexpected failure to create S1AP UE");
// Unpack Transparent Container // Unpack Transparent Container
sourceenb_to_targetenb_transparent_container_s container; sourceenb_to_targetenb_transparent_container_s container;
asn1::cbit_ref bref{msg.protocol_ies.source_to_target_transparent_container.value.data(), asn1::cbit_ref bref{msg->source_to_target_transparent_container.value.data(),
msg.protocol_ies.source_to_target_transparent_container.value.size()}; msg->source_to_target_transparent_container.value.size()};
if (container.unpack(bref) != asn1::SRSASN_SUCCESS) { if (container.unpack(bref) != asn1::SRSASN_SUCCESS) {
logger.warning("Failed to unpack SourceToTargetTransparentContainer"); logger.warning("Failed to unpack SourceToTargetTransparentContainer");
cause.set_protocol().value = cause_protocol_opts::transfer_syntax_error; cause.set_protocol().value = cause_protocol_opts::transfer_syntax_error;
@ -1218,10 +1209,10 @@ void s1ap::send_ho_failure(uint32_t mme_ue_s1ap_id, const asn1::s1ap::cause_c& c
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC); tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
ho_fail_ies_container& container = tx_pdu.unsuccessful_outcome().value.ho_fail().protocol_ies; ho_fail_s& container = tx_pdu.unsuccessful_outcome().value.ho_fail();
container.mme_ue_s1ap_id.value = mme_ue_s1ap_id; container->mme_ue_s1ap_id.value = mme_ue_s1ap_id;
container.cause.value = cause; container->cause.value = cause;
sctp_send_s1ap_pdu(tx_pdu, SRSRAN_INVALID_RNTI, "HandoverFailure"); sctp_send_s1ap_pdu(tx_pdu, SRSRAN_INVALID_RNTI, "HandoverFailure");
} }
@ -1235,24 +1226,24 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
{ {
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_HO_RES_ALLOC);
ho_request_ack_ies_container& container = tx_pdu.successful_outcome().value.ho_request_ack().protocol_ies; ho_request_ack_s& container = tx_pdu.successful_outcome().value.ho_request_ack();
ue* ue_ptr = users.find_ue_mmeid(msg.protocol_ies.mme_ue_s1ap_id.value.value); ue* ue_ptr = users.find_ue_mmeid(msg->mme_ue_s1ap_id.value.value);
if (ue_ptr == nullptr) { if (ue_ptr == nullptr) {
logger.error("The MME-S1AP-UE-ID=%ld is not valid", msg.protocol_ies.mme_ue_s1ap_id.value.value); logger.error("The MME-S1AP-UE-ID=%ld is not valid", msg->mme_ue_s1ap_id.value.value);
return false; return false;
} }
ue_ptr->ctxt.rnti = rnti; ue_ptr->ctxt.rnti = rnti;
ue_ptr->ctxt.enb_cc_idx = enb_cc_idx; ue_ptr->ctxt.enb_cc_idx = enb_cc_idx;
container.mme_ue_s1ap_id.value = msg.protocol_ies.mme_ue_s1ap_id.value.value; container->mme_ue_s1ap_id.value = msg->mme_ue_s1ap_id.value.value;
container.enb_ue_s1ap_id.value = ue_ptr->ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ue_ptr->ctxt.enb_ue_s1ap_id;
// Add admitted E-RABs // Add admitted E-RABs
container.erab_admitted_list.value.resize(admitted_bearers.size()); container->erab_admitted_list.value.resize(admitted_bearers.size());
for (size_t i = 0; i < admitted_bearers.size(); ++i) { for (size_t i = 0; i < admitted_bearers.size(); ++i) {
container.erab_admitted_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM); container->erab_admitted_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ADMITTED_ITEM);
auto& c = container.erab_admitted_list.value[i].value.erab_admitted_item(); auto& c = container->erab_admitted_list.value[i]->erab_admitted_item();
c = admitted_bearers[i]; c = admitted_bearers[i];
if (!args.gtp_advertise_addr.empty()) { if (!args.gtp_advertise_addr.empty()) {
c.transport_layer_address = addr_to_asn1(args.gtp_advertise_addr.c_str()); c.transport_layer_address = addr_to_asn1(args.gtp_advertise_addr.c_str());
@ -1273,12 +1264,12 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
// Add failed to Setup E-RABs // Add failed to Setup E-RABs
if (not not_admitted_bearers.empty()) { if (not not_admitted_bearers.empty()) {
container.erab_failed_to_setup_list_ho_req_ack_present = true; container->erab_failed_to_setup_list_ho_req_ack_present = true;
container.erab_failed_to_setup_list_ho_req_ack.value.resize(not_admitted_bearers.size()); container->erab_failed_to_setup_list_ho_req_ack.value.resize(not_admitted_bearers.size());
for (size_t i = 0; i < not_admitted_bearers.size(); ++i) { for (size_t i = 0; i < not_admitted_bearers.size(); ++i) {
container.erab_failed_to_setup_list_ho_req_ack.value[i].load_info_obj( container->erab_failed_to_setup_list_ho_req_ack.value[i].load_info_obj(
ASN1_S1AP_ID_ERAB_FAILEDTO_SETUP_ITEM_HO_REQ_ACK); ASN1_S1AP_ID_ERAB_FAILEDTO_SETUP_ITEM_HO_REQ_ACK);
auto& erab = container.erab_failed_to_setup_list_ho_req_ack.value[i].value.erab_failedto_setup_item_ho_req_ack(); auto& erab = container->erab_failed_to_setup_list_ho_req_ack.value[i]->erab_failedto_setup_item_ho_req_ack();
erab.erab_id = not_admitted_bearers[i].erab_id; erab.erab_id = not_admitted_bearers[i].erab_id;
erab.cause = not_admitted_bearers[i].cause; erab.cause = not_admitted_bearers[i].cause;
} }
@ -1295,23 +1286,21 @@ bool s1ap::send_ho_req_ack(const asn1::s1ap::ho_request_s& msg,
logger.error("Failed to pack TargeteNBToSourceeNBTransparentContainer"); logger.error("Failed to pack TargeteNBToSourceeNBTransparentContainer");
return false; return false;
} }
container.target_to_source_transparent_container.value.resize(bref.distance_bytes()); container->target_to_source_transparent_container.value.resize(bref.distance_bytes());
memcpy(container.target_to_source_transparent_container.value.data(), pdu->msg, bref.distance_bytes()); memcpy(container->target_to_source_transparent_container.value.data(), pdu->msg, bref.distance_bytes());
return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge"); return sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverRequestAcknowledge");
} }
bool s1ap::handle_mme_status_transfer(const asn1::s1ap::mme_status_transfer_s& msg) bool s1ap::handle_mme_status_transfer(const asn1::s1ap::mme_status_transfer_s& msg)
{ {
ue* u = ue* u = handle_s1apmsg_ue_id(msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value);
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
rrc->set_erab_status( rrc->set_erab_status(u->ctxt.rnti,
u->ctxt.rnti, msg->enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list);
msg.protocol_ies.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list);
return true; return true;
} }
@ -1325,14 +1314,14 @@ void s1ap::send_ho_notify(uint16_t rnti, uint64_t target_eci)
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_NOTIF); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_NOTIF);
ho_notify_ies_container& container = tx_pdu.init_msg().value.ho_notify().protocol_ies; ho_notify_s& container = tx_pdu.init_msg().value.ho_notify();
container.mme_ue_s1ap_id.value = user_ptr->ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = user_ptr->ctxt.mme_ue_s1ap_id.value();
container.enb_ue_s1ap_id.value = user_ptr->ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = user_ptr->ctxt.enb_ue_s1ap_id;
container.eutran_cgi.value = eutran_cgi; container->eutran_cgi.value = eutran_cgi;
container.eutran_cgi.value.cell_id.from_number(target_eci); container->eutran_cgi.value.cell_id.from_number(target_eci);
container.tai.value = tai; container->tai.value = tai;
sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverNotify"); sctp_send_s1ap_pdu(tx_pdu, rnti, "HandoverNotify");
} }
@ -1376,24 +1365,24 @@ bool s1ap::send_error_indication(const asn1::s1ap::cause_c& cause,
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERROR_IND); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERROR_IND);
auto& container = tx_pdu.init_msg().value.error_ind().protocol_ies; auto& container = tx_pdu.init_msg().value.error_ind();
uint16_t rnti = SRSRAN_INVALID_RNTI; uint16_t rnti = SRSRAN_INVALID_RNTI;
container.enb_ue_s1ap_id_present = enb_ue_s1ap_id.has_value(); container->enb_ue_s1ap_id_present = enb_ue_s1ap_id.has_value();
if (enb_ue_s1ap_id.has_value()) { if (enb_ue_s1ap_id.has_value()) {
container.enb_ue_s1ap_id.value = enb_ue_s1ap_id.value(); container->enb_ue_s1ap_id.value = enb_ue_s1ap_id.value();
ue* user_ptr = users.find_ue_enbid(enb_ue_s1ap_id.value()); ue* user_ptr = users.find_ue_enbid(enb_ue_s1ap_id.value());
rnti = user_ptr != nullptr ? user_ptr->ctxt.rnti : SRSRAN_INVALID_RNTI; rnti = user_ptr != nullptr ? user_ptr->ctxt.rnti : SRSRAN_INVALID_RNTI;
} }
container.mme_ue_s1ap_id_present = mme_ue_s1ap_id.has_value(); container->mme_ue_s1ap_id_present = mme_ue_s1ap_id.has_value();
if (mme_ue_s1ap_id.has_value()) { if (mme_ue_s1ap_id.has_value()) {
container.mme_ue_s1ap_id.value = mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = mme_ue_s1ap_id.value();
} }
container.s_tmsi_present = false; container->s_tmsi_present = false;
container.cause_present = true; container->cause_present = true;
container.cause.value = cause; container->cause.value = cause;
return sctp_send_s1ap_pdu(tx_pdu, rnti, "Error Indication"); return sctp_send_s1ap_pdu(tx_pdu, rnti, "Error Indication");
} }
@ -1414,30 +1403,30 @@ bool s1ap::ue::send_initialuemessage(asn1::s1ap::rrc_establishment_cause_e cause
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_INIT_UE_MSG); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_INIT_UE_MSG);
init_ue_msg_ies_container& container = tx_pdu.init_msg().value.init_ue_msg().protocol_ies; init_ue_msg_s& container = tx_pdu.init_msg().value.init_ue_msg();
// S_TMSI // S_TMSI
if (has_tmsi) { if (has_tmsi) {
container.s_tmsi_present = true; container->s_tmsi_present = true;
uint32_to_uint8(m_tmsi, container.s_tmsi.value.m_tmsi.data()); uint32_to_uint8(m_tmsi, container->s_tmsi.value.m_tmsi.data());
container.s_tmsi.value.mmec[0] = mmec; container->s_tmsi.value.mmec[0] = mmec;
} }
// ENB_UE_S1AP_ID // ENB_UE_S1AP_ID
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
// NAS_PDU // NAS_PDU
container.nas_pdu.value.resize(pdu->N_bytes); container->nas_pdu.value.resize(pdu->N_bytes);
memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes); memcpy(container->nas_pdu.value.data(), pdu->msg, pdu->N_bytes);
// TAI // TAI
container.tai.value = s1ap_ptr->tai; container->tai.value = s1ap_ptr->tai;
// EUTRAN_CGI // EUTRAN_CGI
container.eutran_cgi.value = s1ap_ptr->eutran_cgi; container->eutran_cgi.value = s1ap_ptr->eutran_cgi;
// RRC Establishment Cause // RRC Establishment Cause
container.rrc_establishment_cause.value = cause; container->rrc_establishment_cause.value = cause;
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "InitialUEMessage"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "InitialUEMessage");
} }
@ -1451,19 +1440,19 @@ bool s1ap::ue::send_ulnastransport(srsran::unique_byte_buffer_t pdu)
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UL_NAS_TRANSPORT); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UL_NAS_TRANSPORT);
asn1::s1ap::ul_nas_transport_ies_container& container = tx_pdu.init_msg().value.ul_nas_transport().protocol_ies; ul_nas_transport_s& container = tx_pdu.init_msg().value.ul_nas_transport();
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
// NAS PDU // NAS PDU
container.nas_pdu.value.resize(pdu->N_bytes); container->nas_pdu.value.resize(pdu->N_bytes);
memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes); memcpy(container->nas_pdu.value.data(), pdu->msg, pdu->N_bytes);
// EUTRAN CGI // EUTRAN CGI
container.eutran_cgi.value = s1ap_ptr->eutran_cgi; container->eutran_cgi.value = s1ap_ptr->eutran_cgi;
// TAI // TAI
container.tai.value = s1ap_ptr->tai; container->tai.value = s1ap_ptr->tai;
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UplinkNASTransport"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UplinkNASTransport");
} }
@ -1494,13 +1483,12 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause)
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST);
ue_context_release_request_ies_container& container = ue_context_release_request_s& container = tx_pdu.init_msg().value.ue_context_release_request();
tx_pdu.init_msg().value.ue_context_release_request().protocol_ies; container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
// Cause // Cause
container.cause.value = cause; container->cause.value = cause;
release_requested = s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest"); release_requested = s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest");
if (not release_requested) { if (not release_requested) {
@ -1523,9 +1511,9 @@ bool s1ap::ue::send_uectxtreleasecomplete()
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE);
auto& container = tx_pdu.successful_outcome().value.ue_context_release_complete().protocol_ies; auto& container = tx_pdu.successful_outcome().value.ue_context_release_complete();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
// Stop TS1 Reloc Overall // Stop TS1 Reloc Overall
ts1_reloc_overall.stop(); ts1_reloc_overall.stop();
@ -1561,17 +1549,17 @@ void s1ap::ue::ue_ctxt_setup_complete()
if (updated_erabs.empty()) { if (updated_erabs.empty()) {
// It is ICS Failure // It is ICS Failure
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP); tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP);
auto& container = tx_pdu.unsuccessful_outcome().value.init_context_setup_fail().protocol_ies; auto& container = tx_pdu.unsuccessful_outcome().value.init_context_setup_fail();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
if (not failed_cfg_erabs.empty()) { if (not failed_cfg_erabs.empty()) {
container.cause.value = failed_cfg_erabs.front().cause; container->cause.value = failed_cfg_erabs.front().cause;
} else { } else {
logger.warning("Procedure %s,rnti=0x%x - no specified cause for failed configuration", logger.warning("Procedure %s,rnti=0x%x - no specified cause for failed configuration",
s1ap_elem_procs_o::init_msg_c::types_opts{current_state}.to_string(), s1ap_elem_procs_o::init_msg_c::types_opts{current_state}.to_string(),
ctxt.rnti); ctxt.rnti);
container.cause.value.set_misc().value = cause_misc_opts::unspecified; container->cause.value.set_misc().value = cause_misc_opts::unspecified;
} }
s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationFailure"); s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationFailure");
return; return;
@ -1579,23 +1567,23 @@ void s1ap::ue::ue_ctxt_setup_complete()
// It is ICS Response // It is ICS Response
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP);
auto& container = tx_pdu.successful_outcome().value.init_context_setup_resp().protocol_ies; auto& container = tx_pdu.successful_outcome().value.init_context_setup_resp();
// Fill in the MME and eNB IDs // Fill in the MME and eNB IDs
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
// Add list of E-RABs that were not setup // Add list of E-RABs that were not setup
if (not failed_cfg_erabs.empty()) { if (not failed_cfg_erabs.empty()) {
container.erab_failed_to_setup_list_ctxt_su_res_present = true; container->erab_failed_to_setup_list_ctxt_su_res_present = true;
fill_erab_failed_setup_list(container.erab_failed_to_setup_list_ctxt_su_res.value, failed_cfg_erabs); fill_erab_failed_setup_list(container->erab_failed_to_setup_list_ctxt_su_res.value, failed_cfg_erabs);
} }
// Add setup E-RABs // Add setup E-RABs
container.erab_setup_list_ctxt_su_res.value.resize(updated_erabs.size()); container->erab_setup_list_ctxt_su_res.value.resize(updated_erabs.size());
for (size_t i = 0; i < updated_erabs.size(); ++i) { for (size_t i = 0; i < updated_erabs.size(); ++i) {
container.erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES); container->erab_setup_list_ctxt_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_CTXT_SU_RES);
auto& item = container.erab_setup_list_ctxt_su_res.value[i].value.erab_setup_item_ctxt_su_res(); auto& item = container->erab_setup_list_ctxt_su_res.value[i]->erab_setup_item_ctxt_su_res();
item.erab_id = updated_erabs[i]; item.erab_id = updated_erabs[i];
get_erab_addr(item.erab_id, item.transport_layer_address, item.gtp_teid); get_erab_addr(item.erab_id, item.transport_layer_address, item.gtp_teid);
} }
@ -1613,21 +1601,21 @@ bool s1ap::ue::send_erab_setup_response(const erab_id_list& erabs_setup, const e
erab_setup_resp_s& res = tx_pdu.successful_outcome().value.erab_setup_resp(); erab_setup_resp_s& res = tx_pdu.successful_outcome().value.erab_setup_resp();
// Fill in the MME and eNB IDs // Fill in the MME and eNB IDs
res.protocol_ies.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); res->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
res.protocol_ies.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; res->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
// Add list of E-RABs that were not setup // Add list of E-RABs that were not setup
if (not erabs_failed.empty()) { if (not erabs_failed.empty()) {
res.protocol_ies.erab_failed_to_setup_list_bearer_su_res_present = true; res->erab_failed_to_setup_list_bearer_su_res_present = true;
fill_erab_failed_setup_list(res.protocol_ies.erab_failed_to_setup_list_bearer_su_res.value, erabs_failed); fill_erab_failed_setup_list(res->erab_failed_to_setup_list_bearer_su_res.value, erabs_failed);
} }
if (not erabs_setup.empty()) { if (not erabs_setup.empty()) {
res.protocol_ies.erab_setup_list_bearer_su_res_present = true; res->erab_setup_list_bearer_su_res_present = true;
res.protocol_ies.erab_setup_list_bearer_su_res.value.resize(erabs_setup.size()); res->erab_setup_list_bearer_su_res.value.resize(erabs_setup.size());
for (size_t i = 0; i < erabs_setup.size(); ++i) { for (size_t i = 0; i < erabs_setup.size(); ++i) {
res.protocol_ies.erab_setup_list_bearer_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_BEARER_SU_RES); res->erab_setup_list_bearer_su_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_SETUP_ITEM_BEARER_SU_RES);
auto& item = res.protocol_ies.erab_setup_list_bearer_su_res.value[i].value.erab_setup_item_bearer_su_res(); auto& item = res->erab_setup_list_bearer_su_res.value[i]->erab_setup_item_bearer_su_res();
item.erab_id = erabs_setup[i]; item.erab_id = erabs_setup[i];
get_erab_addr(item.erab_id, item.transport_layer_address, item.gtp_teid); get_erab_addr(item.erab_id, item.transport_layer_address, item.gtp_teid);
} }
@ -1644,10 +1632,10 @@ bool s1ap::ue::send_uectxtmodifyresp()
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_MOD); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_MOD);
auto& container = tx_pdu.successful_outcome().value.ue_context_mod_resp().protocol_ies; auto& container = tx_pdu.successful_outcome().value.ue_context_mod_resp();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationResponse"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationResponse");
} }
@ -1660,11 +1648,11 @@ bool s1ap::ue::send_uectxtmodifyfailure(const cause_c& cause)
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_MOD); tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_MOD);
auto& container = tx_pdu.unsuccessful_outcome().value.ue_context_mod_fail().protocol_ies; auto& container = tx_pdu.unsuccessful_outcome().value.ue_context_mod_fail();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.cause.value = cause; container->cause.value = cause;
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationFailure"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationFailure");
} }
@ -1681,26 +1669,26 @@ bool s1ap::ue::send_erab_release_response(const erab_id_list& erabs_released, co
asn1::s1ap::s1ap_pdu_c tx_pdu; asn1::s1ap::s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE);
auto& container = tx_pdu.successful_outcome().value.erab_release_resp().protocol_ies; auto& container = tx_pdu.successful_outcome().value.erab_release_resp();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
// Fill in which E-RABs were successfully released // Fill in which E-RABs were successfully released
if (not erabs_released.empty()) { if (not erabs_released.empty()) {
container.erab_release_list_bearer_rel_comp_present = true; container->erab_release_list_bearer_rel_comp_present = true;
container.erab_release_list_bearer_rel_comp.value.resize(erabs_released.size()); container->erab_release_list_bearer_rel_comp.value.resize(erabs_released.size());
for (size_t i = 0; i < erabs_released.size(); ++i) { for (size_t i = 0; i < erabs_released.size(); ++i) {
container.erab_release_list_bearer_rel_comp.value[i].load_info_obj( container->erab_release_list_bearer_rel_comp.value[i].load_info_obj(
ASN1_S1AP_ID_ERAB_RELEASE_ITEM_BEARER_REL_COMP); ASN1_S1AP_ID_ERAB_RELEASE_ITEM_BEARER_REL_COMP);
container.erab_release_list_bearer_rel_comp.value[i].value.erab_release_item_bearer_rel_comp().erab_id = container->erab_release_list_bearer_rel_comp.value[i]->erab_release_item_bearer_rel_comp().erab_id =
erabs_released[i]; erabs_released[i];
} }
} }
// Fill in which E-RABs were *not* successfully released // Fill in which E-RABs were *not* successfully released
if (not erabs_failed.empty()) { if (not erabs_failed.empty()) {
container.erab_failed_to_release_list_present = true; container->erab_failed_to_release_list_present = true;
fill_erab_failed_setup_list(container.erab_failed_to_release_list.value, erabs_failed); fill_erab_failed_setup_list(container->erab_failed_to_release_list.value, erabs_failed);
} }
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABReleaseResponse"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABReleaseResponse");
@ -1711,25 +1699,25 @@ bool s1ap::ue::send_erab_modify_response(const erab_id_list& erabs_modified, con
asn1::s1ap::s1ap_pdu_c tx_pdu; asn1::s1ap::s1ap_pdu_c tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY);
auto& container = tx_pdu.successful_outcome().value.erab_modify_resp().protocol_ies; auto& container = tx_pdu.successful_outcome().value.erab_modify_resp();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
// Fill in which E-RABs were successfully released // Fill in which E-RABs were successfully released
if (not erabs_modified.empty()) { if (not erabs_modified.empty()) {
container.erab_modify_list_bearer_mod_res_present = true; container->erab_modify_list_bearer_mod_res_present = true;
container.erab_modify_list_bearer_mod_res.value.resize(erabs_modified.size()); container->erab_modify_list_bearer_mod_res.value.resize(erabs_modified.size());
for (uint32_t i = 0; i < container.erab_modify_list_bearer_mod_res.value.size(); i++) { for (uint32_t i = 0; i < container->erab_modify_list_bearer_mod_res.value.size(); i++) {
container.erab_modify_list_bearer_mod_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY_ITEM_BEARER_MOD_RES); container->erab_modify_list_bearer_mod_res.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY_ITEM_BEARER_MOD_RES);
container.erab_modify_list_bearer_mod_res.value[i].value.erab_modify_item_bearer_mod_res().erab_id = container->erab_modify_list_bearer_mod_res.value[i]->erab_modify_item_bearer_mod_res().erab_id =
erabs_modified[i]; erabs_modified[i];
} }
} }
// Fill in which E-RABs were *not* successfully released // Fill in which E-RABs were *not* successfully released
if (not erabs_failed.empty()) { if (not erabs_failed.empty()) {
container.erab_failed_to_modify_list_present = true; container->erab_failed_to_modify_list_present = true;
fill_erab_failed_setup_list(container.erab_failed_to_modify_list.value, erabs_failed); fill_erab_failed_setup_list(container->erab_failed_to_modify_list.value, erabs_failed);
} }
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABModifyResponse"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABModifyResponse");
@ -1744,16 +1732,16 @@ bool s1ap::ue::send_erab_release_indication(const std::vector<uint16_t>& erabs_s
asn1::s1ap::s1ap_pdu_c tx_pdu; asn1::s1ap::s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE_IND); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE_IND);
erab_release_ind_ies_container& container = tx_pdu.init_msg().value.erab_release_ind().protocol_ies; erab_release_ind_s& container = tx_pdu.init_msg().value.erab_release_ind();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
// Fill in which E-RABs were successfully released // Fill in which E-RABs were successfully released
container.erab_released_list.value.resize(erabs_successfully_released.size()); container->erab_released_list.value.resize(erabs_successfully_released.size());
for (size_t i = 0; i < container.erab_released_list.value.size(); ++i) { for (size_t i = 0; i < container->erab_released_list.value.size(); ++i) {
container.erab_released_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); container->erab_released_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
container.erab_released_list.value[i].value.erab_item().erab_id = erabs_successfully_released[i]; container->erab_released_list.value[i]->erab_item().erab_id = erabs_successfully_released[i];
} }
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABReleaseIndication"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABReleaseIndication");
@ -1763,13 +1751,13 @@ bool s1ap::ue::send_ue_cap_info_indication(srsran::unique_byte_buffer_t ue_radio
{ {
asn1::s1ap::s1ap_pdu_c tx_pdu; asn1::s1ap::s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CAP_INFO_IND); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CAP_INFO_IND);
ue_cap_info_ind_ies_container& container = tx_pdu.init_msg().value.ue_cap_info_ind().protocol_ies; ue_cap_info_ind_s& container = tx_pdu.init_msg().value.ue_cap_info_ind();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.ue_radio_cap.value.resize(ue_radio_cap->N_bytes); container->ue_radio_cap.value.resize(ue_radio_cap->N_bytes);
memcpy(container.ue_radio_cap.value.data(), ue_radio_cap->msg, ue_radio_cap->N_bytes); memcpy(container->ue_radio_cap.value.data(), ue_radio_cap->msg, ue_radio_cap->N_bytes);
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UECapabilityInfoIndication"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UECapabilityInfoIndication");
} }
@ -1783,11 +1771,11 @@ void s1ap::ue::send_ho_cancel(const asn1::s1ap::cause_c& cause)
// Send S1AP Handover Cancel // Send S1AP Handover Cancel
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_CANCEL); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_CANCEL);
ho_cancel_ies_container& container = tx_pdu.init_msg().value.ho_cancel().protocol_ies; ho_cancel_s& container = tx_pdu.init_msg().value.ho_cancel();
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.cause.value = cause; container->cause.value = cause;
s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "HandoverCancel"); s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "HandoverCancel");
} }
@ -1942,7 +1930,7 @@ bool s1ap::sctp_send_s1ap_pdu(const asn1::s1ap::s1ap_pdu_c& tx_pdu, uint32_t rnt
return false; return false;
} }
// Reset the state if it is a successful or unsucessfull message // Reset the state if it is a successful or unsuccessfull message
if (tx_pdu.type() == s1ap_pdu_c::types_opts::successful_outcome || if (tx_pdu.type() == s1ap_pdu_c::types_opts::successful_outcome ||
tx_pdu.type() == s1ap_pdu_c::types_opts::unsuccessful_outcome) { tx_pdu.type() == s1ap_pdu_c::types_opts::unsuccessful_outcome) {
if (rnti != SRSRAN_INVALID_RNTI) { if (rnti != SRSRAN_INVALID_RNTI) {
@ -2119,25 +2107,25 @@ bool s1ap::ue::send_ho_required(uint32_t target_eci,
/*** Setup S1AP PDU as HandoverRequired ***/ /*** Setup S1AP PDU as HandoverRequired ***/
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_PREP); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_HO_PREP);
ho_required_ies_container& container = tx_pdu.init_msg().value.ho_required().protocol_ies; ho_required_s& container = tx_pdu.init_msg().value.ho_required();
/*** fill HO Required message ***/ /*** fill HO Required message ***/
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
container.handov_type.value.value = handov_type_opts::intralte; // NOTE: only intra-LTE HO supported container->handov_type.value.value = handov_type_opts::intralte; // NOTE: only intra-LTE HO supported
container.cause.value.set_radio_network().value = cause_radio_network_opts::ho_desirable_for_radio_reason; container->cause.value.set_radio_network().value = cause_radio_network_opts::ho_desirable_for_radio_reason;
container.direct_forwarding_path_availability_present = has_direct_fwd_path; container->direct_forwarding_path_availability_present = has_direct_fwd_path;
if (container.direct_forwarding_path_availability_present) { if (container->direct_forwarding_path_availability_present) {
container.direct_forwarding_path_availability.value.value = container->direct_forwarding_path_availability.value.value =
asn1::s1ap::direct_forwarding_path_availability_opts::direct_path_available; asn1::s1ap::direct_forwarding_path_availability_opts::direct_path_available;
} }
/*** set the target eNB ***/ /*** set the target eNB ***/
container.csg_id_present = false; // NOTE: CSG/hybrid target cell not supported container->csg_id_present = false; // NOTE: CSG/hybrid target cell not supported
container.cell_access_mode_present = false; // only for hybrid cells container->cell_access_mode_present = false; // only for hybrid cells
// no GERAN/UTRAN/PS // no GERAN/UTRAN/PS
auto& targetenb = container.target_id.value.set_targetenb_id(); auto& targetenb = container->target_id.value.set_targetenb_id();
// set PLMN and TAI of target // set PLMN and TAI of target
// NOTE: Only HO without TAU supported. // NOTE: Only HO without TAU supported.
uint16_t tmp16; uint16_t tmp16;
@ -2150,7 +2138,7 @@ bool s1ap::ue::send_ho_required(uint32_t target_eci,
macroenb.from_number(target_eci >> 8U); macroenb.from_number(target_eci >> 8U);
/*** fill the transparent container ***/ /*** fill the transparent container ***/
container.source_to_target_transparent_container_secondary_present = false; container->source_to_target_transparent_container_secondary_present = false;
sourceenb_to_targetenb_transparent_container_s transparent_cntr; sourceenb_to_targetenb_transparent_container_s transparent_cntr;
transparent_cntr.subscriber_profile_idfor_rfp_present = false; // TODO: CHECK transparent_cntr.subscriber_profile_idfor_rfp_present = false; // TODO: CHECK
@ -2158,9 +2146,9 @@ bool s1ap::ue::send_ho_required(uint32_t target_eci,
transparent_cntr.erab_info_list.resize(fwd_erabs.size()); transparent_cntr.erab_info_list.resize(fwd_erabs.size());
for (uint32_t i = 0; i < fwd_erabs.size(); ++i) { for (uint32_t i = 0; i < fwd_erabs.size(); ++i) {
transparent_cntr.erab_info_list[i].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM); transparent_cntr.erab_info_list[i].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM);
transparent_cntr.erab_info_list[i].value.erab_info_list_item().erab_id = fwd_erabs[i]; transparent_cntr.erab_info_list[i]->erab_info_list_item().erab_id = fwd_erabs[i];
transparent_cntr.erab_info_list[i].value.erab_info_list_item().dl_forwarding_present = true; transparent_cntr.erab_info_list[i]->erab_info_list_item().dl_forwarding_present = true;
transparent_cntr.erab_info_list[i].value.erab_info_list_item().dl_forwarding.value = transparent_cntr.erab_info_list[i]->erab_info_list_item().dl_forwarding.value =
dl_forwarding_opts::dl_forwarding_proposed; dl_forwarding_opts::dl_forwarding_proposed;
} }
// - set target cell ID // - set target cell ID
@ -2196,8 +2184,8 @@ bool s1ap::ue::send_ho_required(uint32_t target_eci,
logger.error("Failed to pack transparent container of HO Required message"); logger.error("Failed to pack transparent container of HO Required message");
return false; return false;
} }
container.source_to_target_transparent_container.value.resize(bref.distance_bytes()); container->source_to_target_transparent_container.value.resize(bref.distance_bytes());
memcpy(container.source_to_target_transparent_container.value.data(), buffer->msg, bref.distance_bytes()); memcpy(container->source_to_target_transparent_container.value.data(), buffer->msg, bref.distance_bytes());
// Send to HandoverRequired message to MME // Send to HandoverRequired message to MME
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "Handover Required"); return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "Handover Required");
@ -2211,17 +2199,17 @@ bool s1ap::ue::send_enb_status_transfer_proc(std::vector<bearer_status_info>& be
s1ap_pdu_c tx_pdu; s1ap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ENB_STATUS_TRANSFER); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ENB_STATUS_TRANSFER);
enb_status_transfer_ies_container& container = tx_pdu.init_msg().value.enb_status_transfer().protocol_ies; enb_status_transfer_s& container = tx_pdu.init_msg().value.enb_status_transfer();
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container->enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); container->mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value();
/* Create StatusTransfer transparent container with all the bearer ctxt to transfer */ /* Create StatusTransfer transparent container with all the bearer ctxt to transfer */
auto& list = container.enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list; auto& list = container->enb_status_transfer_transparent_container.value.bearers_subject_to_status_transfer_list;
list.resize(bearer_status_list.size()); list.resize(bearer_status_list.size());
for (uint32_t i = 0; i < list.size(); ++i) { for (uint32_t i = 0; i < list.size(); ++i) {
list[i].load_info_obj(ASN1_S1AP_ID_BEARERS_SUBJECT_TO_STATUS_TRANSFER_ITEM); list[i].load_info_obj(ASN1_S1AP_ID_BEARERS_SUBJECT_TO_STATUS_TRANSFER_ITEM);
auto& asn1bearer = list[i].value.bearers_subject_to_status_transfer_item(); auto& asn1bearer = list[i]->bearers_subject_to_status_transfer_item();
bearer_status_info& item = bearer_status_list[i]; bearer_status_info& item = bearer_status_list[i];
asn1bearer.erab_id = item.erab_id; asn1bearer.erab_id = item.erab_id;

@ -98,12 +98,12 @@ int test_erab_setup(srsran::log_sink_spy& spy, bool qci_exists)
asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes); asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes);
TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS); TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS);
const auto& setupmsg = s1ap_pdu.init_msg().value.erab_setup_request().protocol_ies; const auto& setupmsg = s1ap_pdu.init_msg().value.erab_setup_request();
if (setupmsg.ueaggregate_maximum_bitrate_present) { if (setupmsg->ueaggregate_maximum_bitrate_present) {
rrc.set_aggregate_max_bitrate(rnti, setupmsg.ueaggregate_maximum_bitrate.value); rrc.set_aggregate_max_bitrate(rnti, setupmsg->ueaggregate_maximum_bitrate.value);
} }
for (const auto& item : setupmsg.erab_to_be_setup_list_bearer_su_req.value) { for (const auto& item : setupmsg->erab_to_be_setup_list_bearer_su_req.value) {
const auto& erab = item.value.erab_to_be_setup_item_bearer_su_req(); const auto& erab = item->erab_to_be_setup_item_bearer_su_req();
asn1::s1ap::cause_c cause; asn1::s1ap::cause_c cause;
int ret = rrc.setup_erab(rnti, int ret = rrc.setup_erab(rnti,
erab.erab_id, erab.erab_id,

@ -281,14 +281,14 @@ int test_s1ap_tenb_mobility(test_event test_params)
/* TeNB receives S1AP Handover Request */ /* TeNB receives S1AP Handover Request */
asn1::s1ap::ho_request_s ho_req; asn1::s1ap::ho_request_s ho_req;
ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value.resize(1); ho_req->erab_to_be_setup_list_ho_req.value.resize(1);
auto& erab = ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value[0].value.erab_to_be_setup_item_ho_req(); auto& erab = ho_req->erab_to_be_setup_list_ho_req.value[0]->erab_to_be_setup_item_ho_req();
erab.erab_id = 5; erab.erab_id = 5;
erab.erab_level_qos_params.qci = 9; erab.erab_level_qos_params.qci = 9;
if (test_params == test_event::unknown_qci) { if (test_params == test_event::unknown_qci) {
erab.erab_level_qos_params.qci = 10; erab.erab_level_qos_params.qci = 10;
} }
ho_req.protocol_ies.ue_security_cap.value.integrity_protection_algorithms.set(14, true); ho_req->ue_security_cap.value.integrity_protection_algorithms.set(14, true);
asn1::s1ap::sourceenb_to_targetenb_transparent_container_s container; asn1::s1ap::sourceenb_to_targetenb_transparent_container_s container;
container.target_cell_id.cell_id.from_number(0x19C02); container.target_cell_id.cell_id.from_number(0x19C02);
if (test_params == test_event::wrong_target_cell) { if (test_params == test_event::wrong_target_cell) {
@ -297,9 +297,9 @@ int test_s1ap_tenb_mobility(test_event test_params)
container.erab_info_list_present = true; container.erab_info_list_present = true;
container.erab_info_list.resize(1); container.erab_info_list.resize(1);
container.erab_info_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM); container.erab_info_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_INFO_LIST_ITEM);
container.erab_info_list[0].value.erab_info_list_item().erab_id = 5; container.erab_info_list[0]->erab_info_list_item().erab_id = 5;
container.erab_info_list[0].value.erab_info_list_item().dl_forwarding_present = true; container.erab_info_list[0]->erab_info_list_item().dl_forwarding_present = true;
container.erab_info_list[0].value.erab_info_list_item().dl_forwarding.value = container.erab_info_list[0]->erab_info_list_item().dl_forwarding.value =
asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed; asn1::s1ap::dl_forwarding_opts::dl_forwarding_proposed;
uint8_t ho_prep_container[] = { uint8_t ho_prep_container[] = {
0x0a, 0x10, 0x0b, 0x81, 0x80, 0x00, 0x01, 0x80, 0x00, 0xf3, 0x02, 0x08, 0x00, 0x00, 0x15, 0x80, 0x00, 0x14, 0x0a, 0x10, 0x0b, 0x81, 0x80, 0x00, 0x01, 0x80, 0x00, 0xf3, 0x02, 0x08, 0x00, 0x00, 0x15, 0x80, 0x00, 0x14,
@ -340,8 +340,8 @@ int test_s1ap_tenb_mobility(test_event test_params)
tester.pdcp.bearers[0x46].count(srb_to_lcid(lte_srb::srb2))); tester.pdcp.bearers[0x46].count(srb_to_lcid(lte_srb::srb2)));
TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].enable_encryption); TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].enable_encryption);
TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].enable_integrity); TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].enable_integrity);
sec_cfg.set_security_capabilities(ho_req.protocol_ies.ue_security_cap.value); sec_cfg.set_security_capabilities(ho_req->ue_security_cap.value);
sec_cfg.set_security_key(ho_req.protocol_ies.security_context.value.next_hop_param); sec_cfg.set_security_key(ho_req->security_context.value.next_hop_param);
sec_cfg.regenerate_keys_handover(tester.cfg.cell_list[0].pci, tester.cfg.cell_list[0].dl_earfcn); sec_cfg.regenerate_keys_handover(tester.cfg.cell_list[0].pci, tester.cfg.cell_list[0].dl_earfcn);
srsran::as_security_config_t as_sec_cfg = sec_cfg.get_as_sec_cfg(); srsran::as_security_config_t as_sec_cfg = sec_cfg.get_as_sec_cfg();
TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].sec_cfg.k_rrc_int == as_sec_cfg.k_rrc_int); TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].sec_cfg.k_rrc_int == as_sec_cfg.k_rrc_int);
@ -353,8 +353,7 @@ int test_s1ap_tenb_mobility(test_event test_params)
// Check if S1AP Handover Request ACK send is called // Check if S1AP Handover Request ACK send is called
TESTASSERT(tester.s1ap.last_ho_req_ack.rnti == 0x46); TESTASSERT(tester.s1ap.last_ho_req_ack.rnti == 0x46);
TESTASSERT(tester.s1ap.last_ho_req_ack.ho_cmd_pdu != nullptr); TESTASSERT(tester.s1ap.last_ho_req_ack.ho_cmd_pdu != nullptr);
TESTASSERT(tester.s1ap.last_ho_req_ack.admitted_bearers.size() == TESTASSERT(tester.s1ap.last_ho_req_ack.admitted_bearers.size() == ho_req->erab_to_be_setup_list_ho_req.value.size());
ho_req.protocol_ies.erab_to_be_setup_list_ho_req.value.size());
ho_cmd_s ho_cmd; ho_cmd_s ho_cmd;
asn1::cbit_ref bref{tester.s1ap.last_ho_req_ack.ho_cmd_pdu->msg, tester.s1ap.last_ho_req_ack.ho_cmd_pdu->N_bytes}; asn1::cbit_ref bref{tester.s1ap.last_ho_req_ack.ho_cmd_pdu->msg, tester.s1ap.last_ho_req_ack.ho_cmd_pdu->N_bytes};
TESTASSERT(ho_cmd.unpack(bref) == asn1::SRSASN_SUCCESS); TESTASSERT(ho_cmd.unpack(bref) == asn1::SRSASN_SUCCESS);
@ -369,11 +368,11 @@ int test_s1ap_tenb_mobility(test_event test_params)
// Receives MMEStatusTransfer // Receives MMEStatusTransfer
asn1::s1ap::bearers_subject_to_status_transfer_list_l bearers; asn1::s1ap::bearers_subject_to_status_transfer_list_l bearers;
bearers.resize(1); bearers.resize(1);
bearers[0].value.bearers_subject_to_status_transfer_item().erab_id = 5; bearers[0]->bearers_subject_to_status_transfer_item().erab_id = 5;
bearers[0].value.bearers_subject_to_status_transfer_item().dl_coun_tvalue.pdcp_sn = 100; bearers[0]->bearers_subject_to_status_transfer_item().dl_coun_tvalue.pdcp_sn = 100;
bearers[0].value.bearers_subject_to_status_transfer_item().dl_coun_tvalue.hfn = 3; bearers[0]->bearers_subject_to_status_transfer_item().dl_coun_tvalue.hfn = 3;
bearers[0].value.bearers_subject_to_status_transfer_item().ul_coun_tvalue.pdcp_sn = 120; bearers[0]->bearers_subject_to_status_transfer_item().ul_coun_tvalue.pdcp_sn = 120;
bearers[0].value.bearers_subject_to_status_transfer_item().ul_coun_tvalue.hfn = 4; bearers[0]->bearers_subject_to_status_transfer_item().ul_coun_tvalue.hfn = 4;
tester.rrc.set_erab_status(0x46, bearers); tester.rrc.set_erab_status(0x46, bearers);
TESTASSERT(tester.pdcp.bearers.count(0x46)); TESTASSERT(tester.pdcp.bearers.count(0x46));
TESTASSERT(tester.pdcp.bearers[0x46].count(3)); TESTASSERT(tester.pdcp.bearers[0x46].count(3));

@ -137,9 +137,8 @@ int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srsran::timer_handler& timers, u
asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes); asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes);
TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS); TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS);
rrc.setup_ue_ctxt(rnti, s1ap_pdu.init_msg().value.init_context_setup_request()); rrc.setup_ue_ctxt(rnti, s1ap_pdu.init_msg().value.init_context_setup_request());
for (auto& item : for (auto& item : s1ap_pdu.init_msg().value.init_context_setup_request()->erab_to_be_setup_list_ctxt_su_req.value) {
s1ap_pdu.init_msg().value.init_context_setup_request().protocol_ies.erab_to_be_setup_list_ctxt_su_req.value) { const auto& erab = item->erab_to_be_setup_item_ctxt_su_req();
const auto& erab = item.value.erab_to_be_setup_item_ctxt_su_req();
asn1::s1ap::cause_c cause; asn1::s1ap::cause_c cause;
TESTASSERT(rrc.setup_erab(rnti, TESTASSERT(rrc.setup_erab(rnti,
erab.erab_id, erab.erab_id,

@ -201,9 +201,9 @@ void add_rnti(s1ap& s1ap_obj, mme_dummy& mme)
TESTASSERT(s1ap_pdu.unpack(cbref) == SRSRAN_SUCCESS); TESTASSERT(s1ap_pdu.unpack(cbref) == SRSRAN_SUCCESS);
TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::successful_outcome); TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::successful_outcome);
TESTASSERT(s1ap_pdu.successful_outcome().proc_code == ASN1_S1AP_ID_INIT_CONTEXT_SETUP); TESTASSERT(s1ap_pdu.successful_outcome().proc_code == ASN1_S1AP_ID_INIT_CONTEXT_SETUP);
const auto& resp = s1ap_pdu.successful_outcome().value.init_context_setup_resp().protocol_ies; const auto& resp = s1ap_pdu.successful_outcome().value.init_context_setup_resp();
TESTASSERT(resp.erab_setup_list_ctxt_su_res.value.size() > 0); TESTASSERT(resp->erab_setup_list_ctxt_su_res.value.size() > 0);
TESTASSERT(not resp.erab_failed_to_setup_list_ctxt_su_res_present); TESTASSERT(not resp->erab_failed_to_setup_list_ctxt_su_res_present);
} }
enum class test_event { success, wrong_erabid_mod, wrong_mme_s1ap_id, repeated_erabid_mod }; enum class test_event { success, wrong_erabid_mod, wrong_mme_s1ap_id, repeated_erabid_mod };
@ -244,13 +244,13 @@ void test_s1ap_erab_setup(test_event event)
int flags = 0; int flags = 0;
asn1::s1ap::s1ap_pdu_c mod_req_pdu; asn1::s1ap::s1ap_pdu_c mod_req_pdu;
mod_req_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY); mod_req_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY);
auto& protocols = mod_req_pdu.init_msg().value.erab_modify_request().protocol_ies; auto& protocols = mod_req_pdu.init_msg().value.erab_modify_request();
protocols.enb_ue_s1ap_id.value = 1; protocols->enb_ue_s1ap_id.value = 1;
protocols.mme_ue_s1ap_id.value = event == test_event::wrong_mme_s1ap_id ? 2 : 1; protocols->mme_ue_s1ap_id.value = event == test_event::wrong_mme_s1ap_id ? 2 : 1;
auto& erab_list = protocols.erab_to_be_modified_list_bearer_mod_req.value; auto& erab_list = protocols->erab_to_be_modified_list_bearer_mod_req.value;
erab_list.resize(2); erab_list.resize(2);
erab_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_TO_BE_MODIFIED_ITEM_BEARER_MOD_REQ); erab_list[0].load_info_obj(ASN1_S1AP_ID_ERAB_TO_BE_MODIFIED_ITEM_BEARER_MOD_REQ);
auto* erab_ptr = &erab_list[0].value.erab_to_be_modified_item_bearer_mod_req(); auto* erab_ptr = &erab_list[0]->erab_to_be_modified_item_bearer_mod_req();
erab_ptr->erab_id = 5; erab_ptr->erab_id = 5;
erab_ptr->erab_level_qos_params.qci = 9; erab_ptr->erab_level_qos_params.qci = 9;
erab_ptr->erab_level_qos_params.alloc_retention_prio.prio_level = 15; erab_ptr->erab_level_qos_params.alloc_retention_prio.prio_level = 15;
@ -261,7 +261,7 @@ void test_s1ap_erab_setup(test_event event)
erab_ptr->nas_pdu.resize(1); erab_ptr->nas_pdu.resize(1);
erab_ptr->nas_pdu[0] = 0; erab_ptr->nas_pdu[0] = 0;
erab_list[1] = erab_list[0]; erab_list[1] = erab_list[0];
erab_ptr = &erab_list[1].value.erab_to_be_modified_item_bearer_mod_req(); erab_ptr = &erab_list[1]->erab_to_be_modified_item_bearer_mod_req();
erab_ptr->erab_id = event == test_event::repeated_erabid_mod ? 5 : 6; erab_ptr->erab_id = event == test_event::repeated_erabid_mod ? 5 : 6;
if (event == test_event::wrong_erabid_mod) { if (event == test_event::wrong_erabid_mod) {
rrc.next_erabs_failed_to_modify.push_back(6); rrc.next_erabs_failed_to_modify.push_back(6);
@ -282,34 +282,33 @@ void test_s1ap_erab_setup(test_event event)
// See TS 36.413, Section 10.6 - Handling of AP ID // See TS 36.413, Section 10.6 - Handling of AP ID
TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::init_msg); TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::init_msg);
TESTASSERT(s1ap_pdu.init_msg().proc_code == ASN1_S1AP_ID_ERROR_IND); TESTASSERT(s1ap_pdu.init_msg().proc_code == ASN1_S1AP_ID_ERROR_IND);
auto& protocol_ies = s1ap_pdu.init_msg().value.error_ind().protocol_ies; auto& err_ind = s1ap_pdu.init_msg().value.error_ind();
TESTASSERT(protocol_ies.mme_ue_s1ap_id_present and protocol_ies.mme_ue_s1ap_id.value.value == 2); TESTASSERT(err_ind->mme_ue_s1ap_id_present and err_ind->mme_ue_s1ap_id.value.value == 2);
TESTASSERT(protocol_ies.enb_ue_s1ap_id_present and protocol_ies.enb_ue_s1ap_id.value.value == 1); TESTASSERT(err_ind->enb_ue_s1ap_id_present and err_ind->enb_ue_s1ap_id.value.value == 1);
TESTASSERT(rrc.last_released_rnti == 0x46); TESTASSERT(rrc.last_released_rnti == 0x46);
return; return;
} }
TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::successful_outcome); TESTASSERT(s1ap_pdu.type().value == asn1::s1ap::s1ap_pdu_c::types_opts::successful_outcome);
TESTASSERT(s1ap_pdu.successful_outcome().proc_code == ASN1_S1AP_ID_ERAB_MODIFY); TESTASSERT(s1ap_pdu.successful_outcome().proc_code == ASN1_S1AP_ID_ERAB_MODIFY);
auto& protocol_ies = s1ap_pdu.successful_outcome().value.erab_modify_resp().protocol_ies; auto& erab_mod = s1ap_pdu.successful_outcome().value.erab_modify_resp();
if (event == test_event::wrong_erabid_mod) { if (event == test_event::wrong_erabid_mod) {
TESTASSERT(protocol_ies.erab_modify_list_bearer_mod_res_present); TESTASSERT(erab_mod->erab_modify_list_bearer_mod_res_present);
TESTASSERT(protocol_ies.erab_modify_list_bearer_mod_res.value.size() == 1); TESTASSERT(erab_mod->erab_modify_list_bearer_mod_res.value.size() == 1);
TESTASSERT(protocol_ies.erab_modify_list_bearer_mod_res.value[0].value.erab_modify_item_bearer_mod_res().erab_id == TESTASSERT(erab_mod->erab_modify_list_bearer_mod_res.value[0]->erab_modify_item_bearer_mod_res().erab_id == 5);
5); TESTASSERT(erab_mod->erab_failed_to_modify_list_present);
TESTASSERT(protocol_ies.erab_failed_to_modify_list_present); TESTASSERT(erab_mod->erab_failed_to_modify_list.value.size() == 1);
TESTASSERT(protocol_ies.erab_failed_to_modify_list.value.size() == 1); auto& erab_item = erab_mod->erab_failed_to_modify_list.value[0]->erab_item();
auto& erab_item = protocol_ies.erab_failed_to_modify_list.value[0].value.erab_item();
TESTASSERT(erab_item.erab_id == 6); TESTASSERT(erab_item.erab_id == 6);
TESTASSERT(erab_item.cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network); TESTASSERT(erab_item.cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network);
TESTASSERT(erab_item.cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::unknown_erab_id); TESTASSERT(erab_item.cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::unknown_erab_id);
return; return;
} }
if (event == test_event::repeated_erabid_mod) { if (event == test_event::repeated_erabid_mod) {
TESTASSERT(not protocol_ies.erab_modify_list_bearer_mod_res_present); TESTASSERT(not erab_mod->erab_modify_list_bearer_mod_res_present);
TESTASSERT(protocol_ies.erab_failed_to_modify_list_present); TESTASSERT(erab_mod->erab_failed_to_modify_list_present);
TESTASSERT(protocol_ies.erab_failed_to_modify_list.value.size() == 1); TESTASSERT(erab_mod->erab_failed_to_modify_list.value.size() == 1);
auto& erab_item = protocol_ies.erab_failed_to_modify_list.value[0].value.erab_item(); auto& erab_item = erab_mod->erab_failed_to_modify_list.value[0]->erab_item();
TESTASSERT(erab_item.erab_id == 5); TESTASSERT(erab_item.erab_id == 5);
TESTASSERT(erab_item.cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network); TESTASSERT(erab_item.cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network);
TESTASSERT(erab_item.cause.radio_network().value == TESTASSERT(erab_item.cause.radio_network().value ==
@ -317,10 +316,10 @@ void test_s1ap_erab_setup(test_event event)
return; return;
} }
TESTASSERT(protocol_ies.erab_modify_list_bearer_mod_res_present); TESTASSERT(erab_mod->erab_modify_list_bearer_mod_res_present);
TESTASSERT(not protocol_ies.erab_failed_to_modify_list_present); TESTASSERT(not erab_mod->erab_failed_to_modify_list_present);
TESTASSERT(protocol_ies.erab_modify_list_bearer_mod_res.value.size() == 2); TESTASSERT(erab_mod->erab_modify_list_bearer_mod_res.value.size() == 2);
auto& erab_item = protocol_ies.erab_modify_list_bearer_mod_res.value[0].value.erab_modify_item_bearer_mod_res(); auto& erab_item = erab_mod->erab_modify_list_bearer_mod_res.value[0]->erab_modify_item_bearer_mod_res();
TESTASSERT(erab_item.erab_id == 5); TESTASSERT(erab_item.erab_id == 5);
} }

@ -644,8 +644,6 @@ bool nas::handle_service_request(uint32_t m_tmsi,
srsran::console("Service Request -- Short MAC valid\n"); srsran::console("Service Request -- Short MAC valid\n");
nas_logger.info("Service Request -- Short MAC valid"); nas_logger.info("Service Request -- Short MAC valid");
if (ecm_ctx->state == ECM_STATE_CONNECTED) { if (ecm_ctx->state == ECM_STATE_CONNECTED) {
nas_logger.error("Service Request -- User is ECM CONNECTED");
// Release previous context // Release previous context
nas_logger.info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d", nas_logger.info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d",
ecm_ctx->enb_ue_s1ap_id, ecm_ctx->enb_ue_s1ap_id,
@ -697,8 +695,6 @@ bool nas::handle_service_request(uint32_t m_tmsi,
srsran::console("Service Request -- Short MAC invalid\n"); srsran::console("Service Request -- Short MAC invalid\n");
nas_logger.info("Service Request -- Short MAC invalid"); nas_logger.info("Service Request -- Short MAC invalid");
if (ecm_ctx->state == ECM_STATE_CONNECTED) { if (ecm_ctx->state == ECM_STATE_CONNECTED) {
nas_logger.error("Service Request -- User is ECM CONNECTED");
// Release previous context // Release previous context
nas_logger.info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d", nas_logger.info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d",
ecm_ctx->enb_ue_s1ap_id, ecm_ctx->enb_ue_s1ap_id,

@ -25,7 +25,6 @@
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/int_helpers.h" #include "srsran/common/int_helpers.h"
#include "srsran/common/liblte_security.h" #include "srsran/common/liblte_security.h"
#include <endian.h>
namespace srsepc { namespace srsepc {
@ -83,24 +82,23 @@ bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint1
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_INIT_CONTEXT_SETUP);
asn1::s1ap::init_context_setup_request_ies_container& in_ctx_req = asn1::s1ap::init_context_setup_request_s& in_ctx_req = tx_pdu.init_msg().value.init_context_setup_request();
tx_pdu.init_msg().value.init_context_setup_request().protocol_ies;
// Add MME and eNB S1AP Ids // Add MME and eNB S1AP Ids
in_ctx_req.mme_ue_s1ap_id.value = ecm_ctx->mme_ue_s1ap_id; in_ctx_req->mme_ue_s1ap_id.value = ecm_ctx->mme_ue_s1ap_id;
in_ctx_req.enb_ue_s1ap_id.value = ecm_ctx->enb_ue_s1ap_id; in_ctx_req->enb_ue_s1ap_id.value = ecm_ctx->enb_ue_s1ap_id;
// UE-AMBR // UE-AMBR
in_ctx_req.ueaggregate_maximum_bitrate.value.ueaggregate_maximum_bit_rate_dl = 1000000000; in_ctx_req->ueaggregate_maximum_bitrate.value.ueaggregate_maximum_bit_rate_dl = 1000000000;
in_ctx_req.ueaggregate_maximum_bitrate.value.ueaggregate_maximum_bit_rate_ul = 1000000000; in_ctx_req->ueaggregate_maximum_bitrate.value.ueaggregate_maximum_bit_rate_ul = 1000000000;
// Number of E-RABs to be setup // Number of E-RABs to be setup
in_ctx_req.erab_to_be_setup_list_ctxt_su_req.value.resize(1); in_ctx_req->erab_to_be_setup_list_ctxt_su_req.value.resize(1);
in_ctx_req.erab_to_be_setup_list_ctxt_su_req.value[0].load_info_obj(ASN1_S1AP_ID_ERAB_TO_BE_SETUP_ITEM_CTXT_SU_REQ); in_ctx_req->erab_to_be_setup_list_ctxt_su_req.value[0].load_info_obj(ASN1_S1AP_ID_ERAB_TO_BE_SETUP_ITEM_CTXT_SU_REQ);
// Setup eRAB context // Setup eRAB context
asn1::s1ap::erab_to_be_setup_item_ctxt_su_req_s& erab_ctx_req = asn1::s1ap::erab_to_be_setup_item_ctxt_su_req_s& erab_ctx_req =
in_ctx_req.erab_to_be_setup_list_ctxt_su_req.value[0].value.erab_to_be_setup_item_ctxt_su_req(); in_ctx_req->erab_to_be_setup_list_ctxt_su_req.value[0]->erab_to_be_setup_item_ctxt_su_req();
erab_ctx_req.erab_id = esm_ctx->erab_id; erab_ctx_req.erab_id = esm_ctx->erab_id;
// Setup E-RAB QoS parameters // Setup E-RAB QoS parameters
@ -121,21 +119,21 @@ bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint1
// Set UE security capabilities and k_enb // Set UE security capabilities and k_enb
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (sec_ctx->ue_network_cap.eea[i + 1] == true) { if (sec_ctx->ue_network_cap.eea[i + 1] == true) {
in_ctx_req.ue_security_cap.value.encryption_algorithms.set(16 - i, true); // EEA supported in_ctx_req->ue_security_cap.value.encryption_algorithms.set(16 - i, true); // EEA supported
} else { } else {
in_ctx_req.ue_security_cap.value.encryption_algorithms.set(16 - i, false); // EEA not supported in_ctx_req->ue_security_cap.value.encryption_algorithms.set(16 - i, false); // EEA not supported
} }
if (sec_ctx->ue_network_cap.eia[i + 1] == true) { if (sec_ctx->ue_network_cap.eia[i + 1] == true) {
in_ctx_req.ue_security_cap.value.integrity_protection_algorithms.set(16 - i, true); // EIA supported in_ctx_req->ue_security_cap.value.integrity_protection_algorithms.set(16 - i, true); // EIA supported
} else { } else {
in_ctx_req.ue_security_cap.value.integrity_protection_algorithms.set(16 - i, false); // EIA not supported in_ctx_req->ue_security_cap.value.integrity_protection_algorithms.set(16 - i, false); // EIA not supported
} }
} }
// Get K eNB // Get K eNB
// memcpy(in_ctx_req.security_key.value.data(),sec_ctx->k_enb, 32); // memcpy(in_ctx_req->security_key.value.data(),sec_ctx->k_enb, 32);
for (uint8_t i = 0; i < 32; ++i) { for (uint8_t i = 0; i < 32; ++i) {
in_ctx_req.security_key.value.data()[31 - i] = sec_ctx->k_enb[i]; in_ctx_req->security_key.value.data()[31 - i] = sec_ctx->k_enb[i];
} }
m_logger.info(sec_ctx->k_enb, 32, "Initial Context Setup Request -- Key eNB (k_enb)"); m_logger.info(sec_ctx->k_enb, 32, "Initial Context Setup Request -- Key eNB (k_enb)");
@ -166,8 +164,8 @@ bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint1
m_logger.info( m_logger.info(
"Initial Context -- S1-U TEID 0x%" PRIx64 ". IP %s ", erab_ctx_req.gtp_teid.to_number(), inet_ntoa(addr)); "Initial Context -- S1-U TEID 0x%" PRIx64 ". IP %s ", erab_ctx_req.gtp_teid.to_number(), inet_ntoa(addr));
m_logger.info("Initial Context Setup Request -- eNB UE S1AP Id %d, MME UE S1AP Id %" PRIu64 "", m_logger.info("Initial Context Setup Request -- eNB UE S1AP Id %d, MME UE S1AP Id %" PRIu64 "",
in_ctx_req.enb_ue_s1ap_id.value.value, in_ctx_req->enb_ue_s1ap_id.value.value,
in_ctx_req.mme_ue_s1ap_id.value.value); in_ctx_req->mme_ue_s1ap_id.value.value);
m_logger.info("Initial Context Setup Request -- E-RAB id %d", erab_ctx_req.erab_id); m_logger.info("Initial Context Setup Request -- E-RAB id %d", erab_ctx_req.erab_id);
m_logger.info("Initial Context Setup Request -- S1-U TEID 0x%" PRIu64 ". IP %s ", m_logger.info("Initial Context Setup Request -- S1-U TEID 0x%" PRIu64 ". IP %s ",
erab_ctx_req.gtp_teid.to_number(), erab_ctx_req.gtp_teid.to_number(),
@ -182,7 +180,7 @@ bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint1
bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response( bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
const asn1::s1ap::init_context_setup_resp_s& in_ctxt_resp) const asn1::s1ap::init_context_setup_resp_s& in_ctxt_resp)
{ {
uint32_t mme_ue_s1ap_id = in_ctxt_resp.protocol_ies.mme_ue_s1ap_id.value.value; uint32_t mme_ue_s1ap_id = in_ctxt_resp->mme_ue_s1ap_id.value.value;
nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id); nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == nullptr) { if (nas_ctx == nullptr) {
m_logger.error("Could not find UE's context in active UE's map"); m_logger.error("Could not find UE's context in active UE's map");
@ -195,12 +193,11 @@ bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
srsran::console("Received Initial Context Setup Response\n"); srsran::console("Received Initial Context Setup Response\n");
// Setup E-RABs // Setup E-RABs
for (const asn1::s1ap::protocol_ie_single_container_s<asn1::s1ap::erab_setup_item_ctxt_su_res_ies_o>& ie_container : for (const asn1::protocol_ie_single_container_s<asn1::s1ap::erab_setup_item_ctxt_su_res_ies_o>& ie_container :
in_ctxt_resp.protocol_ies.erab_setup_list_ctxt_su_res.value) { in_ctxt_resp->erab_setup_list_ctxt_su_res.value) {
// Get E-RAB setup context item and E-RAB Id // Get E-RAB setup context item and E-RAB Id
const asn1::s1ap::erab_setup_item_ctxt_su_res_s& erab_setup_item_ctxt = const asn1::s1ap::erab_setup_item_ctxt_su_res_s& erab_setup_item_ctxt = ie_container->erab_setup_item_ctxt_su_res();
ie_container.value.erab_setup_item_ctxt_su_res(); uint8_t erab_id = erab_setup_item_ctxt.erab_id;
uint8_t erab_id = erab_setup_item_ctxt.erab_id;
// Make sure we requested the context setup // Make sure we requested the context setup
esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_id]; esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[erab_id];
@ -241,7 +238,7 @@ bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(const asn1::s1ap::ue_context_release_request_s& ue_rel, bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(const asn1::s1ap::ue_context_release_request_s& ue_rel,
struct sctp_sndrcvinfo* enb_sri) struct sctp_sndrcvinfo* enb_sri)
{ {
uint32_t mme_ue_s1ap_id = ue_rel.protocol_ies.mme_ue_s1ap_id.value.value; uint32_t mme_ue_s1ap_id = ue_rel->mme_ue_s1ap_id.value.value;
m_logger.info("Received UE Context Release Request. MME-UE S1AP Id: %d", mme_ue_s1ap_id); m_logger.info("Received UE Context Release Request. MME-UE S1AP Id: %d", mme_ue_s1ap_id);
srsran::console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id); srsran::console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);
@ -313,14 +310,13 @@ bool s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas* nas_ctx)
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE);
asn1::s1ap::ue_context_release_cmd_ies_container& ctx_rel_cmd = asn1::s1ap::ue_context_release_cmd_s& ctx_rel_cmd = tx_pdu.init_msg().value.ue_context_release_cmd();
tx_pdu.init_msg().value.ue_context_release_cmd().protocol_ies; ctx_rel_cmd->ue_s1ap_ids.value.set(asn1::s1ap::ue_s1ap_ids_c::types_opts::ue_s1ap_id_pair);
ctx_rel_cmd.ue_s1ap_ids.value.set(asn1::s1ap::ue_s1ap_ids_c::types_opts::ue_s1ap_id_pair); ctx_rel_cmd->ue_s1ap_ids.value.ue_s1ap_id_pair().mme_ue_s1ap_id = nas_ctx->m_ecm_ctx.mme_ue_s1ap_id;
ctx_rel_cmd.ue_s1ap_ids.value.ue_s1ap_id_pair().mme_ue_s1ap_id = nas_ctx->m_ecm_ctx.mme_ue_s1ap_id; ctx_rel_cmd->ue_s1ap_ids.value.ue_s1ap_id_pair().enb_ue_s1ap_id = nas_ctx->m_ecm_ctx.enb_ue_s1ap_id;
ctx_rel_cmd.ue_s1ap_ids.value.ue_s1ap_id_pair().enb_ue_s1ap_id = nas_ctx->m_ecm_ctx.enb_ue_s1ap_id;
ctx_rel_cmd.cause.value.set(asn1::s1ap::cause_c::types_opts::nas); ctx_rel_cmd->cause.value.set(asn1::s1ap::cause_c::types_opts::nas);
ctx_rel_cmd.cause.value.nas().value = asn1::s1ap::cause_nas_opts::options::normal_release; ctx_rel_cmd->cause.value.nas().value = asn1::s1ap::cause_nas_opts::options::normal_release;
// Send Reply to eNB // Send Reply to eNB
if (!m_s1ap->s1ap_tx_pdu(tx_pdu, &nas_ctx->m_ecm_ctx.enb_sri)) { if (!m_s1ap->s1ap_tx_pdu(tx_pdu, &nas_ctx->m_ecm_ctx.enb_sri)) {
@ -333,7 +329,7 @@ bool s1ap_ctx_mngmt_proc::send_ue_context_release_command(nas* nas_ctx)
bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(const asn1::s1ap::ue_context_release_complete_s& rel_comp) bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(const asn1::s1ap::ue_context_release_complete_s& rel_comp)
{ {
uint32_t mme_ue_s1ap_id = rel_comp.protocol_ies.mme_ue_s1ap_id.value.value; uint32_t mme_ue_s1ap_id = rel_comp->mme_ue_s1ap_id.value.value;
m_logger.info("Received UE Context Release Complete. MME-UE S1AP Id: %d", mme_ue_s1ap_id); m_logger.info("Received UE Context Release Complete. MME-UE S1AP Id: %d", mme_ue_s1ap_id);
srsran::console("Received UE Context Release Complete. MME-UE S1AP Id %d\n", mme_ue_s1ap_id); srsran::console("Received UE Context Release Complete. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);

@ -79,19 +79,19 @@ bool s1ap_erab_mngmt_proc::send_erab_release_command(uint32_t enb_
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE);
asn1::s1ap::erab_release_cmd_ies_container& erab_rel_cmd = tx_pdu.init_msg().value.erab_release_cmd().protocol_ies; asn1::s1ap::erab_release_cmd_s& erab_rel_cmd = tx_pdu.init_msg().value.erab_release_cmd();
// Add MME and eNB S1AP Ids // Add MME and eNB S1AP Ids
erab_rel_cmd.mme_ue_s1ap_id.value = mme_ue_s1ap_id; erab_rel_cmd->mme_ue_s1ap_id.value = mme_ue_s1ap_id;
erab_rel_cmd.enb_ue_s1ap_id.value = enb_ue_s1ap_id; erab_rel_cmd->enb_ue_s1ap_id.value = enb_ue_s1ap_id;
// Number of E-RABs to be setup // Number of E-RABs to be setup
erab_rel_cmd.erab_to_be_released_list.value.resize(erabs_to_release.size()); erab_rel_cmd->erab_to_be_released_list.value.resize(erabs_to_release.size());
for (uint32_t i = 0; i < erab_rel_cmd.erab_to_be_released_list.value.size(); i++) { for (uint32_t i = 0; i < erab_rel_cmd->erab_to_be_released_list.value.size(); i++) {
erab_rel_cmd.erab_to_be_released_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); erab_rel_cmd->erab_to_be_released_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM);
erab_rel_cmd.erab_to_be_released_list.value[i].value.erab_item().erab_id = erabs_to_release[i]; erab_rel_cmd->erab_to_be_released_list.value[i]->erab_item().erab_id = erabs_to_release[i];
erab_rel_cmd.erab_to_be_released_list.value[i].value.erab_item().cause.set(asn1::s1ap::cause_c::types::misc); erab_rel_cmd->erab_to_be_released_list.value[i]->erab_item().cause.set(asn1::s1ap::cause_c::types::misc);
erab_rel_cmd.erab_to_be_released_list.value[i].value.erab_item().cause.misc() = erab_rel_cmd->erab_to_be_released_list.value[i]->erab_item().cause.misc() =
asn1::s1ap::cause_misc_opts::unspecified; asn1::s1ap::cause_misc_opts::unspecified;
m_logger.info("Sending release comman to %d", erabs_to_release[i]); m_logger.info("Sending release comman to %d", erabs_to_release[i]);
} }
@ -115,21 +115,20 @@ bool s1ap_erab_mngmt_proc::send_erab_modify_request(uint32_t
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY); tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_ERAB_MODIFY);
asn1::s1ap::erab_modify_request_ies_container& erab_mod_req = asn1::s1ap::erab_modify_request_s& erab_mod_req = tx_pdu.init_msg().value.erab_modify_request();
tx_pdu.init_msg().value.erab_modify_request().protocol_ies;
// Add MME and eNB S1AP Ids // Add MME and eNB S1AP Ids
erab_mod_req.enb_ue_s1ap_id.value = enb_ue_s1ap_id; erab_mod_req->enb_ue_s1ap_id.value = enb_ue_s1ap_id;
erab_mod_req.mme_ue_s1ap_id.value = mme_ue_s1ap_id; erab_mod_req->mme_ue_s1ap_id.value = mme_ue_s1ap_id;
// Number of E-RABs to be setup // Number of E-RABs to be setup
erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value.resize(erabs_to_modify.size()); erab_mod_req->erab_to_be_modified_list_bearer_mod_req.value.resize(erabs_to_modify.size());
uint32_t i = 0; uint32_t i = 0;
for (auto erab_it = erabs_to_modify.begin(); erab_it != erabs_to_modify.end(); erab_it++) { for (auto erab_it = erabs_to_modify.begin(); erab_it != erabs_to_modify.end(); erab_it++) {
erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value[i].load_info_obj( erab_mod_req->erab_to_be_modified_list_bearer_mod_req.value[i].load_info_obj(
ASN1_S1AP_ID_ERAB_TO_BE_MODIFIED_ITEM_BEARER_MOD_REQ); ASN1_S1AP_ID_ERAB_TO_BE_MODIFIED_ITEM_BEARER_MOD_REQ);
asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s& erab_to_mod = asn1::s1ap::erab_to_be_modified_item_bearer_mod_req_s& erab_to_mod =
erab_mod_req.erab_to_be_modified_list_bearer_mod_req.value[i].value.erab_to_be_modified_item_bearer_mod_req(); erab_mod_req->erab_to_be_modified_list_bearer_mod_req.value[i]->erab_to_be_modified_item_bearer_mod_req();
erab_to_mod.erab_id = erab_it->first; erab_to_mod.erab_id = erab_it->first;
erab_to_mod.erab_level_qos_params.qci = erab_it->second; erab_to_mod.erab_level_qos_params.qci = erab_it->second;
erab_to_mod.erab_level_qos_params.alloc_retention_prio.prio_level = 15; // lowest erab_to_mod.erab_level_qos_params.alloc_retention_prio.prio_level = 15; // lowest

@ -126,36 +126,35 @@ bool s1ap_mngmt_proc::handle_s1_setup_request(const asn1::s1ap::s1_setup_request
*/ */
bool s1ap_mngmt_proc::unpack_s1_setup_request(const asn1::s1ap::s1_setup_request_s& msg, enb_ctx_t* enb_ctx) bool s1ap_mngmt_proc::unpack_s1_setup_request(const asn1::s1ap::s1_setup_request_s& msg, enb_ctx_t* enb_ctx)
{ {
uint8_t enb_id_bits[32]; uint8_t enb_id_bits[32];
uint32_t plmn = 0; uint32_t plmn = 0;
uint16_t tac, bplmn; uint16_t tac, bplmn;
uint32_t tmp32 = 0; uint32_t tmp32 = 0;
const asn1::s1ap::s1_setup_request_ies_container& s1_req = msg.protocol_ies; const asn1::s1ap::s1_setup_request_s& s1_req = msg;
// eNB Name // eNB Name
enb_ctx->enb_name_present = s1_req.enbname_present; enb_ctx->enb_name_present = s1_req->enbname_present;
if (s1_req.enbname_present) { if (s1_req->enbname_present) {
enb_ctx->enb_name = s1_req.enbname.value.to_string(); enb_ctx->enb_name = s1_req->enbname.value.to_string();
} }
// eNB Id // eNB Id
enb_ctx->enb_id = s1_req.global_enb_id.value.enb_id.macro_enb_id().to_number(); enb_ctx->enb_id = s1_req->global_enb_id.value.enb_id.macro_enb_id().to_number();
// PLMN Id // PLMN Id
((uint8_t*)&plmn)[1] = s1_req.global_enb_id.value.plm_nid[0]; ((uint8_t*)&plmn)[1] = s1_req->global_enb_id.value.plm_nid[0];
((uint8_t*)&plmn)[2] = s1_req.global_enb_id.value.plm_nid[1]; ((uint8_t*)&plmn)[2] = s1_req->global_enb_id.value.plm_nid[1];
((uint8_t*)&plmn)[3] = s1_req.global_enb_id.value.plm_nid[2]; ((uint8_t*)&plmn)[3] = s1_req->global_enb_id.value.plm_nid[2];
enb_ctx->plmn = ntohl(plmn); enb_ctx->plmn = ntohl(plmn);
srsran::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc); srsran::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc);
// SupportedTAs // SupportedTAs
enb_ctx->nof_supported_ta = s1_req.supported_tas.value.size(); enb_ctx->nof_supported_ta = s1_req->supported_tas.value.size();
for (uint16_t i = 0; i < enb_ctx->nof_supported_ta; i++) { for (uint16_t i = 0; i < enb_ctx->nof_supported_ta; i++) {
const asn1::s1ap::supported_tas_item_s& tas = s1_req.supported_tas.value[i]; const asn1::s1ap::supported_tas_item_s& tas = s1_req->supported_tas.value[i];
// TAC // TAC
((uint8_t*)&enb_ctx->tacs[i])[0] = tas.tac[0]; ((uint8_t*)&enb_ctx->tacs[i])[0] = tas.tac[0];
((uint8_t*)&enb_ctx->tacs[i])[1] = tas.tac[1]; ((uint8_t*)&enb_ctx->tacs[i])[1] = tas.tac[1];
@ -172,7 +171,7 @@ bool s1ap_mngmt_proc::unpack_s1_setup_request(const asn1::s1ap::s1_setup_request
} }
// Default Paging DRX // Default Paging DRX
enb_ctx->drx.value = s1_req.default_paging_drx.value; enb_ctx->drx.value = s1_req->default_paging_drx.value;
return true; return true;
} }
@ -182,10 +181,10 @@ bool s1ap_mngmt_proc::send_s1_setup_failure(asn1::s1ap::cause_misc_opts::options
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_S1_SETUP); tx_pdu.set_unsuccessful_outcome().load_info_obj(ASN1_S1AP_ID_S1_SETUP);
asn1::s1ap::s1_setup_fail_ies_container& s1_fail = tx_pdu.unsuccessful_outcome().value.s1_setup_fail().protocol_ies; asn1::s1ap::s1_setup_fail_s& s1_fail = tx_pdu.unsuccessful_outcome().value.s1_setup_fail();
s1_fail.cause.value.set(asn1::s1ap::cause_c::types_opts::misc); s1_fail->cause.value.set(asn1::s1ap::cause_c::types_opts::misc);
s1_fail.cause.value.misc().value = cause; s1_fail->cause.value.misc().value = cause;
m_s1ap->s1ap_tx_pdu(tx_pdu, enb_sri); m_s1ap->s1ap_tx_pdu(tx_pdu, enb_sri);
return true; return true;
@ -198,20 +197,20 @@ bool s1ap_mngmt_proc::send_s1_setup_response(const s1ap_args_t& s1ap_args, struc
s1ap_pdu_t tx_pdu; s1ap_pdu_t tx_pdu;
tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_S1_SETUP); tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_S1_SETUP);
asn1::s1ap::s1_setup_resp_ies_container& s1_resp = tx_pdu.successful_outcome().value.s1_setup_resp().protocol_ies; asn1::s1ap::s1_setup_resp_s& s1_resp = tx_pdu.successful_outcome().value.s1_setup_resp();
// MME Name // MME Name
s1_resp.mm_ename_present = true; s1_resp->mm_ename_present = true;
s1_resp.mm_ename.value.from_string(s1ap_args.mme_name); s1_resp->mm_ename.value.from_string(s1ap_args.mme_name);
// Served GUMEIs // Served GUMEIs
s1_resp.served_gummeis.value.resize(1); // TODO Only one served GUMMEI supported s1_resp->served_gummeis.value.resize(1); // TODO Only one served GUMMEI supported
uint32_t plmn = 0; uint32_t plmn = 0;
srsran::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn); srsran::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
plmn = htonl(plmn); plmn = htonl(plmn);
asn1::s1ap::served_gummeis_item_s& serv_gummei = s1_resp.served_gummeis.value[0]; asn1::s1ap::served_gummeis_item_s& serv_gummei = s1_resp->served_gummeis.value[0];
serv_gummei.served_plmns.resize(1); serv_gummei.served_plmns.resize(1);
serv_gummei.served_plmns[0][0] = ((uint8_t*)&plmn)[1]; serv_gummei.served_plmns[0][0] = ((uint8_t*)&plmn)[1];
@ -224,7 +223,7 @@ bool s1ap_mngmt_proc::send_s1_setup_response(const s1ap_args_t& s1ap_args, struc
serv_gummei.served_mmecs.resize(1); // Only one MMEC served serv_gummei.served_mmecs.resize(1); // Only one MMEC served
serv_gummei.served_mmecs[0].from_number(s1ap_args.mme_code); serv_gummei.served_mmecs[0].from_number(s1ap_args.mme_code);
s1_resp.relative_mme_capacity.value = 255; s1_resp->relative_mme_capacity.value = 255;
if (!m_s1ap->s1ap_tx_pdu(tx_pdu, enb_sri)) { if (!m_s1ap->s1ap_tx_pdu(tx_pdu, enb_sri)) {
m_logger.error("Error sending S1 Setup Response."); m_logger.error("Error sending S1 Setup Response.");

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save