Merge branch 'next' into agpl_next

master
Codebot 3 years ago committed by Your Name
commit b87b760326

@ -23,13 +23,16 @@ if(NOT LIMESDR_FOUND)
find_path(LIMESDR_INCLUDE_DIRS
NAMES LimeSuite.h
HINTS $ENV{LIMESUITE_DIR}/include
PATHS ${LIMESDR_PKG_INCLUDE_DIRS}
/usr/include/lime
/usr/local/include/lime
$ENV{LIMESUITE_DIR}/include/lime
)
find_library(LIMESDR_LIBRARIES
NAMES LimeSuite
HINTS $ENV{LIMESUITE_DIR}/lib
PATHS ${LIMESDR_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib

@ -24,6 +24,8 @@ if(NOT SOAPYSDR_FOUND)
find_path(SOAPYSDR_INCLUDE_DIRS
NAMES Device.h
HINTS $ENV{SOAPY_DIR}/include
$ENV{SOAPY_DIR}/include/SoapySDR
PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS}
/usr/include/SoapySDR
/usr/local/include/SoapySDR
@ -31,6 +33,7 @@ if(NOT SOAPYSDR_FOUND)
find_library(SOAPYSDR_LIBRARIES
NAMES SoapySDR
HINTS $ENV{SOAPY_DIR}/lib
PATHS ${SOAPYSDR_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib

@ -20,18 +20,21 @@
if(NOT BLADERF_FOUND)
pkg_check_modules (BLADERF_PKG libbladeRF)
find_path(BLADERF_INCLUDE_DIRS NAMES libbladeRF.h
PATHS
${BLADERF_PKG_INCLUDE_DIRS}
/usr/include
/usr/local/include
find_path(BLADERF_INCLUDE_DIRS
NAMES libbladeRF.h
HINTS $ENV{BLADERF_DIR}/include
PATHS ${BLADERF_PKG_INCLUDE_DIRS}
/usr/include
/usr/local/include
)
find_library(BLADERF_LIBRARIES NAMES bladeRF
PATHS
${BLADERF_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
find_library(BLADERF_LIBRARIES
NAMES bladeRF
HINTS $ENV{BLADERF_DIR}/lib
PATHS ${BLADERF_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES)

@ -33,7 +33,7 @@ class optional
public:
using value_type = T;
optional() : has_val_(false) {}
optional() : has_val_(false), empty() {}
optional(const T& t) : has_val_(true) { storage.emplace(t); }
optional(T&& t) : has_val_(true) { storage.emplace(std::move(t)); }
optional(const optional<T>& other) : has_val_(other.has_value())
@ -107,8 +107,11 @@ public:
}
private:
bool has_val_;
detail::type_storage<T> storage;
bool has_val_;
union {
char empty;
detail::type_storage<T> storage;
};
};
template <typename T>

@ -40,6 +40,9 @@ public:
// Return frequency of given NR-ARFCN in Hz
double nr_arfcn_to_freq(uint32_t nr_arfcn);
// Frequency in Hz to NR-ARFCN
uint32_t freq_to_nr_arfcn(double freq);
// Possible values of delta f_raster in Table 5.4.2.3-1 and Table 5.4.2.3-2
enum delta_f_raster_t {
DEFAULT = 0, // for bands with 2 possible values for delta_f_raster (e.g. 15 and 30 kHz), the lower is chosen
@ -68,6 +71,17 @@ public:
*/
uint16_t get_band_from_dl_arfcn(uint32_t arfcn) const;
/**
* @brief Get the respective UL ARFCN of a DL ARFCN
*
* For paired spectrum (FDD) the function returns the respective ARFCN in the same band.
* For unparied spectrum (TDD) the function returns the same ARFCN.
*
* @param dl_arfcn The DL ARFCN
* @return uint32_t the UL ARFCN
*/
uint32_t get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn) const;
/**
* @brief Selects the SSB pattern case according to the band number and subcarrier spacing
* @remark Described by TS 38.101-1 Table 5.4.3.3-1: Applicable SS raster entries per operating band
@ -84,6 +98,22 @@ public:
*/
srsran_duplex_mode_t get_duplex_mode(uint16_t band) const;
/**
* @brief Compute the DL center frequency for a NR carrier
*
* @param carrier Const Reference to a carrier struct including PRB, abs. frequency point A and carrier offset.
* @return double Frequency in Hz
*/
double get_dl_center_freq(const srsran_carrier_nr_t& carrier);
/**
* @brief Compute the UL center frequency for a NR carrier
*
* @param carrier Const Reference to a carrier struct including PRB, abs. frequency point A and carrier offset.
* @return double Frequency in Hz
*/
double get_ul_center_freq(const srsran_carrier_nr_t& carrier);
class sync_raster_t
{
protected:
@ -115,6 +145,9 @@ public:
sync_raster_t get_sync_raster(uint16_t band, srsran_subcarrier_spacing_t scs) const;
private:
// internal helper
double get_center_freq_from_abs_freq_point_a(uint32_t nof_prb, uint32_t freq_point_a_arfcn);
// Elements of TS 38.101-1 Table 5.2-1: NR operating bands in FR1
struct nr_operating_band {
uint16_t band;
@ -163,25 +196,36 @@ private:
}};
struct nr_raster_params {
double freq_range_start;
double freq_range_end;
double delta_F_global_kHz;
double F_REF_Offs_MHz;
uint32_t N_REF_Offs;
uint32_t N_REF_min;
uint32_t N_REF_max;
bool operator==(const nr_raster_params& rhs) const
{
return freq_range_start == rhs.freq_range_start && freq_range_end == rhs.freq_range_end &&
delta_F_global_kHz == rhs.delta_F_global_kHz && F_REF_Offs_MHz == rhs.F_REF_Offs_MHz &&
N_REF_Offs == rhs.N_REF_Offs && N_REF_min == rhs.N_REF_min && N_REF_max == rhs.N_REF_max;
}
};
// Helper to calculate F_REF according to Table 5.4.2.1-1
nr_raster_params get_raster_params(uint32_t nr_arfcn);
nr_raster_params get_raster_params(double freq);
bool is_valid_raster_param(const nr_raster_params& raster);
static const uint32_t max_nr_arfcn = 3279165;
static constexpr std::array<nr_raster_params, 3> nr_fr_params = {{
// clang-format off
// Frequency range 0 - 3000 MHz
{5, 0.0, 0, 0, 599999},
{0, 3000, 5, 0.0, 0, 0, 599999},
// Frequency range 3000 - 24250 MHz
{15, 3000.0, 600000, 600000, 2016666},
{3000, 24250, 15, 3000.0, 600000, 600000, 2016666},
// Frequency range 24250 - 100000 MHz
{60, 24250.08, 2016667, 2016667, max_nr_arfcn}
{24250, 100000, 60, 24250.08, 2016667, 2016667, max_nr_arfcn}
// clang-format on
}};

@ -23,25 +23,23 @@
#define SRSRAN_S1AP_PCAP_H
#include "srsran/common/pcap.h"
#include <string>
namespace srsran {
class s1ap_pcap
{
public:
s1ap_pcap()
{
enable_write = false;
pcap_file = NULL;
}
s1ap_pcap() = default;
void enable();
void open(const char* filename);
void open(const char* filename_);
void close();
void write_s1ap(uint8_t* pdu, uint32_t pdu_len_bytes);
private:
bool enable_write;
FILE* pcap_file;
bool enable_write = false;
std::string filename;
FILE* pcap_file = nullptr;
};
} // namespace srsran

@ -24,6 +24,8 @@
#include "srsran/srslog/bundled/fmt/format.h"
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
@ -128,6 +130,49 @@ const char* to_c_str(fmt::basic_memory_buffer<char, N>& mem_buffer)
return mem_buffer.data();
}
static inline bool replace(std::string& str, const std::string& from, const std::string& to)
{
size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
static inline std::vector<std::string> split_string(const std::string& str, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
static inline void get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len)
{
const char* pos = key_str.c_str();
for (uint count = 0; count < len; count++) {
sscanf(pos, "%2hhx", &key[count]);
pos += 2;
}
return;
}
static inline std::string hex_string(uint8_t* hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < size; i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
} // namespace srsran
#endif // SRSRAN_STRING_HELPERS_H

@ -135,8 +135,15 @@ public:
class rrc_nr_interface_rrc
{
public:
/// Request addition of NR carrier for UE (TODO: add configuration check, QCI, security, etc.)
virtual int sgnb_addition_request(uint16_t eutra_rnti) = 0;
struct sgnb_addition_req_params_t {
uint32_t eps_bearer_id;
// add configuration check
// E-RAB Parameters, Tunnel address (IP address, TEID)
// QCI, security, etc
};
/// Request addition of NR carrier for UE
virtual int sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params) = 0;
/// Provide information whether the requested configuration was applied successfully by the UE
virtual int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) = 0;
@ -146,16 +153,26 @@ public:
class rrc_eutra_interface_rrc_nr
{
public:
/**
* @brief List of parameters included in the SgNB addition Ack message
* @param nr_secondary_cell_group_cfg_r15 Encoded part of the RRC Reconfiguration
* @param nr_radio_bearer_cfg1_r15 Encoded part of the RRC Reconfiguration
* @param eps_bearer_id ID of the transfered bearer
*/
struct sgnb_addition_ack_params_t {
uint16_t nr_rnti = SRSRAN_INVALID_RNTI; // RNTI that was assigned to the UE
asn1::dyn_octstring nr_secondary_cell_group_cfg_r15;
asn1::dyn_octstring nr_radio_bearer_cfg1_r15;
uint32_t eps_bearer_id = 0; // (list of) successfully transfered EPS bearers
};
/**
* @brief Signal successful addition of UE
*
* @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
* @param nr_secondary_cell_group_cfg_r15 Encoded part of the RRC Reconfiguration
* @param nr_radio_bearer_cfg1_r15 Encoded part of the RRC Reconfiguration
* @param params Parameter list
*/
virtual void sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) = 0;
virtual void sgnb_addition_ack(uint16_t eutra_rnti, sgnb_addition_ack_params_t params) = 0;
/**
* @brief Signal unsuccessful SgNB addition
@ -167,9 +184,10 @@ public:
/**
* @brief Signal completion of SgNB addition after UE (with new NR identity) has attached
*
* @param nr_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
* @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
* @param nr_rnti The RNTI that has been assigned to the UE on the SgNB
*/
virtual void sgnb_addition_complete(uint16_t eutra_rnti) = 0;
virtual void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) = 0;
};
} // namespace srsenb

@ -30,8 +30,7 @@ class mac_interface_rrc_nr
{
public:
// Provides cell configuration including SIB periodicity, etc.
virtual int cell_cfg(const sched_interface::cell_cfg_t& cell,
srsran::const_span<sched_nr_interface::cell_cfg_t> nr_cells) = 0;
virtual int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) = 0;
/// 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) = 0;

@ -140,7 +140,6 @@ struct rach_nr_cfg_t {
uint32_t powerRampingStep;
uint32_t ra_responseWindow;
uint32_t ra_ContentionResolutionTimer;
bool skip_rar;
rach_nr_cfg_t() { reset(); }
void reset()
@ -150,7 +149,6 @@ struct rach_nr_cfg_t {
powerRampingStep = 0;
preambleTransMax = 0;
ra_responseWindow = 0;
skip_rar = false;
}
};

@ -63,8 +63,9 @@ public:
} mac_nr_grant_dl_t;
typedef struct {
srsran::unique_byte_buffer_t payload; // TB when decoded successfully, nullptr otherwise
bool ack; // HARQ information
uint32_t rx_slot_idx; // Slot when DL TB has been decoded
srsran::unique_byte_buffer_t payload; // TB when decoded successfully, nullptr otherwise
bool ack; // HARQ information
} tb_action_dl_result_t;
// UL grant as conveyed between PHY and MAC
@ -221,7 +222,8 @@ public:
} tx_request_t;
// MAC informs PHY about UL grant included in RAR PDU
virtual int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
virtual int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
uint16_t rnti,
srsran_rnti_type_t rnti_type) = 0;

@ -0,0 +1,93 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_BSR_NR_H
#define SRSRAN_BSR_NR_H
#include <stdint.h>
/**
* @brief Buffer size format definition and levels according to 3GPP TS 38.321 version 15.3.0
*
* Shared between UE and gNB MAC layers
*/
namespace srsran {
// TS 38.321 Sec 6.1.3.1
typedef enum { SHORT_BSR, LONG_BSR, SHORT_TRUNC_BSR, LONG_TRUNC_BSR } bsr_format_nr_t;
// TS 38.321, Table 6.1.3.1-1 Buffer size levels (in bytes) for 5-bit Buffer Size field, all values <= except marked
static const uint32_t buffer_size_levels_5bit_max_idx = 31;
static uint32_t buffer_size_levels_5bit[buffer_size_levels_5bit_max_idx + 1] = {
/* == */ 0, 10, 14, 20, 28, 38, 53, 74, 102, 142, 198,
276, 384, 535, 745, 1038, 1446, 2014, 2806, 3909, 5446, 7587,
10570, 14726, 20516, 28581, 39818, 55474, 77284, 107669, 150000, /* > */ 150000};
// TS 38.321, Table 6.1.3.1-2: Buffer size levels (in bytes) for 8-bit Buffer Size field, all values <= except marked
static const uint32_t buffer_size_levels_8bit_max_idx = 254;
static uint32_t buffer_size_levels_8bit[buffer_size_levels_8bit_max_idx + 1] = {
/* == */ 0, 10, 11, 12, 13,
14, 15, 16, 17, 18,
19, 20, 22, 23, 25,
26, 28, 30, 32, 34,
36, 38, 40, 43, 46,
49, 52, 55, 59, 62,
66, 71, 75, 80, 85,
91, 97, 103, 110, 117,
124, 132, 141, 150, 160,
170, 181, 193, 205, 218,
233, 248, 264, 281, 299,
318, 339, 361, 384, 409,
436, 464, 494, 526, 560,
597, 635, 677, 720, 767,
817, 870, 926, 987, 1051,
1119, 1191, 1269, 1351, 1439,
1532, 1631, 1737, 1850, 1970,
2098, 2234, 2379, 2533, 2698,
2873, 3059, 3258, 3469, 3694,
3934, 4189, 4461, 4751, 5059,
5387, 5737, 6109, 6506, 6928,
7378, 7857, 8367, 8910, 9488,
10104, 10760, 11458, 12202, 12994,
13838, 14736, 15692, 16711, 17795,
18951, 20181, 21491, 22885, 24371,
25953, 27638, 29431, 31342, 33376,
35543, 37850, 40307, 42923, 45709,
48676, 51836, 55200, 58784, 62599,
66663, 70990, 75598, 80505, 85730,
91295, 97221, 103532, 110252, 117409,
125030, 133146, 141789, 150992, 160793,
171231, 182345, 194182, 206786, 220209,
234503, 249725, 265935, 283197, 301579,
321155, 342002, 364202, 387842, 413018,
439827, 468377, 498780, 531156, 565634,
602350, 641449, 683087, 727427, 774645,
824928, 878475, 935498, 996222, 1060888,
1129752, 1203085, 1281179, 1364342, 1452903,
1547213, 1647644, 1754595, 1868488, 1989774,
2118933, 2256475, 2402946, 2558924, 2725027,
2901912, 3090279, 3290873, 3504487, 3731968,
3974215, 4232186, 4506902, 4799451, 5110989,
5442750, 5796046, 6172275, 6572925, 6999582,
7453933, 7937777, 8453028, 9001725, 9586039,
10208280, 10870913, 11576557, 12328006, 13128233,
13980403, 14887889, 15854280, 16883401, 17979324,
19146385, 20389201, 21712690, 23122088, 24622972,
26221280, 27923336, 29735875, 31666069, 33721553,
35910462, 38241455, 40723756, 43367187, 46182206,
49179951, 52372284, 55771835, 59392055, 63247269,
67352729, 71724679, 76380419, 81338368, /* > */ 81338368};
} // namespace srsran
#endif // SRSRAN_BSR_NR_H

@ -372,7 +372,8 @@ typedef enum SRSRAN_API {
typedef struct SRSRAN_API {
uint32_t pci;
uint32_t absolute_frequency_ssb;
uint32_t absolute_frequency_point_a;
uint32_t dl_absolute_frequency_point_a;
uint32_t ul_absolute_frequency_point_a;
uint32_t offset_to_carrier; ///< Offset between point A and the lowest subcarrier of the lowest RB
srsran_subcarrier_spacing_t scs;
uint32_t nof_prb; ///< @brief See TS 38.101-1 Table 5.3.2-1 for more details

@ -188,10 +188,12 @@ sink& fetch_stderr_sink(const std::string& id = "stderr",
/// Specifying a max_size value different to zero will make the sink create a
/// new file each time the current file exceeds this value. The units of
/// max_size are bytes.
/// Setting force_flush to true will flush the sink after every write.
/// NOTE: Any '#' characters in the path will get removed.
sink& fetch_file_sink(const std::string& path,
size_t max_size = 0,
std::unique_ptr<log_formatter> f = get_default_log_formatter());
size_t max_size = 0,
bool force_flush = false,
std::unique_ptr<log_formatter> f = get_default_log_formatter());
/// Returns an instance of a sink that writes into syslog
/// preamble: The string prepended to every message, If ident is "", the program name is used.

@ -157,9 +157,10 @@ srslog_sink* srslog_fetch_stderr_sink(void);
* Specifying a max_size value different to zero will make the sink create a
* new file each time the current file exceeds this value. The units of
* max_size are bytes.
* Setting force_flush to true will flush the sink after every write.
* NOTE: Any '#' characters in the id will get removed.
*/
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size);
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size, srslog_bool force_flush);
#ifdef __cplusplus
}

@ -1358,11 +1358,13 @@ bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrie
}
// As the carrier structure requires parameters from different objects, set fields separately
out_carrier_nr->absolute_frequency_ssb = absolute_frequency_ssb;
out_carrier_nr->absolute_frequency_point_a = asn1_freq_info_dl.absolute_freq_point_a;
out_carrier_nr->offset_to_carrier = asn1_freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier;
out_carrier_nr->nof_prb = asn1_freq_info_dl.scs_specific_carrier_list[0].carrier_bw;
out_carrier_nr->scs = scs;
out_carrier_nr->absolute_frequency_ssb = absolute_frequency_ssb;
out_carrier_nr->dl_absolute_frequency_point_a = asn1_freq_info_dl.absolute_freq_point_a;
out_carrier_nr->ul_absolute_frequency_point_a =
out_carrier_nr->dl_absolute_frequency_point_a; // needs to be updated for FDD
out_carrier_nr->offset_to_carrier = asn1_freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier;
out_carrier_nr->nof_prb = asn1_freq_info_dl.scs_specific_carrier_list[0].carrier_bw;
out_carrier_nr->scs = scs;
return true;
}

@ -38,10 +38,22 @@ constexpr std::array<srsran_band_helper::nr_band_ss_raster, srsran_band_helper::
double srsran_band_helper::nr_arfcn_to_freq(uint32_t nr_arfcn)
{
nr_raster_params params = get_raster_params(nr_arfcn);
if (not is_valid_raster_param(params)) {
return 0.0;
}
return (params.F_REF_Offs_MHz * 1e6 + params.delta_F_global_kHz * (nr_arfcn - params.N_REF_Offs) * 1e3);
}
// Implements 5.4.2.1 in TS 38.401
uint32_t srsran_band_helper::freq_to_nr_arfcn(double freq)
{
nr_raster_params params = get_raster_params(freq);
if (not is_valid_raster_param(params)) {
return 0;
}
return (((freq + params.F_REF_Offs_MHz * 1e6) / 1e3 / params.delta_F_global_kHz) + params.N_REF_Offs);
}
// Implements 5.4.2.1 in TS 38.104
std::vector<uint32_t> srsran_band_helper::get_bands_nr(uint32_t nr_arfcn,
srsran_band_helper::delta_f_raster_t delta_f_raster)
{
@ -88,6 +100,44 @@ uint16_t srsran_band_helper::get_band_from_dl_arfcn(uint32_t arfcn) const
return UINT16_MAX;
}
uint32_t srsran_band_helper::get_ul_arfcn_from_dl_arfcn(uint32_t dl_arfcn) const
{
// return same ARFCN for TDD bands
if (get_duplex_mode(get_band_from_dl_arfcn(dl_arfcn)) == SRSRAN_DUPLEX_MODE_TDD) {
return dl_arfcn;
}
// derive UL ARFCN for FDD bands
for (const auto& band : nr_band_table_fr1) {
if (band.band == get_band_from_dl_arfcn(dl_arfcn)) {
uint32_t offset = (dl_arfcn - band.dl_nref_first) / band.dl_nref_step;
return (band.ul_nref_first + offset * band.ul_nref_step);
}
}
return 0;
}
double srsran_band_helper::get_dl_center_freq(const srsran_carrier_nr_t& carrier)
{
return get_center_freq_from_abs_freq_point_a(carrier.nof_prb, carrier.dl_absolute_frequency_point_a);
}
double srsran_band_helper::get_ul_center_freq(const srsran_carrier_nr_t& carrier)
{
return get_center_freq_from_abs_freq_point_a(carrier.nof_prb, carrier.ul_absolute_frequency_point_a);
}
double srsran_band_helper::get_center_freq_from_abs_freq_point_a(uint32_t nof_prb, uint32_t freq_point_a_arfcn)
{
// for FR1 unit of resources blocks for freq calc is always 180kHz regardless for actual SCS of carrier
// TODO: add offset_to_carrier
double abs_freq_point_a_freq = nr_arfcn_to_freq(freq_point_a_arfcn);
return abs_freq_point_a_freq +
(nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(srsran_subcarrier_spacing_t::srsran_subcarrier_spacing_15kHz) *
SRSRAN_NRE);
}
srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) const
{
// Look for the given band and SCS
@ -189,4 +239,24 @@ srsran_band_helper::nr_raster_params srsran_band_helper::get_raster_params(uint3
return {}; // return empty params
}
srsran_band_helper::nr_raster_params srsran_band_helper::get_raster_params(double freq)
{
for (auto& fr : nr_fr_params) {
if (freq >= fr.freq_range_start * 1e6 && freq <= fr.freq_range_end * 1e6) {
return fr;
}
}
return {}; // return empty params
}
bool srsran_band_helper::is_valid_raster_param(const srsran_band_helper::nr_raster_params& raster)
{
for (auto& fr : nr_fr_params) {
if (fr == raster) {
return true;
}
}
return false;
}
} // namespace srsran

@ -126,7 +126,11 @@ void enb_bearer_manager::add_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id, sr
auto user_it = users_map.find(rnti);
if (user_it == users_map.end()) {
// add empty bearer map
auto p = users_map.insert(rnti, srsran::detail::ue_bearer_manager_impl{});
auto p = users_map.insert(rnti, srsran::detail::ue_bearer_manager_impl{});
if (!p) {
logger.error("Bearers: Unable to add a new bearer map for rnti=0x%x", rnti);
return;
}
user_it = p.value();
}
@ -158,7 +162,14 @@ void enb_bearer_manager::remove_eps_bearer(uint16_t rnti, uint8_t eps_bearer_id)
void enb_bearer_manager::rem_user(uint16_t rnti)
{
auto user_it = users_map.find(rnti);
if (user_it == users_map.end()) {
logger.error("Bearers: No EPS bearer registered for rnti=0x%x", rnti);
return;
}
logger.info("Bearers: Removed rnti=0x%x from EPS bearer manager", rnti);
users_map.erase(user_it);
}
bool enb_bearer_manager::has_active_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id)

@ -75,24 +75,24 @@ phy_cfg_nr_default_t::reference_cfg_t::reference_cfg_t(const std::string& args)
void phy_cfg_nr_default_t::make_carrier_custom_10MHz(srsran_carrier_nr_t& carrier)
{
carrier.nof_prb = 52;
carrier.max_mimo_layers = 1;
carrier.pci = 500;
carrier.absolute_frequency_point_a = 633928;
carrier.absolute_frequency_ssb = 634176;
carrier.offset_to_carrier = 0;
carrier.scs = srsran_subcarrier_spacing_15kHz;
carrier.nof_prb = 52;
carrier.max_mimo_layers = 1;
carrier.pci = 500;
carrier.dl_absolute_frequency_point_a = 633928;
carrier.absolute_frequency_ssb = 634176;
carrier.offset_to_carrier = 0;
carrier.scs = srsran_subcarrier_spacing_15kHz;
}
void phy_cfg_nr_default_t::make_carrier_custom_20MHz(srsran_carrier_nr_t& carrier)
{
carrier.nof_prb = 106;
carrier.max_mimo_layers = 1;
carrier.pci = 500;
carrier.absolute_frequency_point_a = 633928;
carrier.absolute_frequency_ssb = 634176;
carrier.offset_to_carrier = 0;
carrier.scs = srsran_subcarrier_spacing_15kHz;
carrier.nof_prb = 106;
carrier.max_mimo_layers = 1;
carrier.pci = 500;
carrier.dl_absolute_frequency_point_a = 633928;
carrier.absolute_frequency_ssb = 634176;
carrier.offset_to_carrier = 0;
carrier.scs = srsran_subcarrier_spacing_15kHz;
}
void phy_cfg_nr_default_t::make_tdd_custom_6_4(srsran_tdd_config_nr_t& tdd)

@ -30,14 +30,15 @@ void s1ap_pcap::enable()
{
enable_write = true;
}
void s1ap_pcap::open(const char* filename)
void s1ap_pcap::open(const char* filename_)
{
pcap_file = DLT_PCAP_Open(S1AP_LTE_DLT, filename);
filename = filename_;
pcap_file = DLT_PCAP_Open(S1AP_LTE_DLT, filename.c_str());
enable_write = true;
}
void s1ap_pcap::close()
{
fprintf(stdout, "Saving S1AP PCAP file\n");
fprintf(stdout, "Saving S1AP PCAP file (DLT=%d) to %s\n", S1AP_LTE_DLT, filename.c_str());
DLT_PCAP_Close(pcap_file);
}

@ -42,6 +42,21 @@ int bands_test_nr()
// b32 b75
TESTASSERT(bands.nr_arfcn_to_freq(290400) == 1452.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(294400) == 1472.0e6);
// b5
TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6);
TESTASSERT(bands.freq_to_nr_arfcn(881.5e6) == 176300);
TESTASSERT(bands.get_ul_arfcn_from_dl_arfcn(176300) == 167300);
TESTASSERT(bands.nr_arfcn_to_freq(167300) == 836.5e6);
// check actual freqs for FDD carrier (example values are for 52 PRB)
srsran_carrier_nr_t carrier = {};
carrier.dl_absolute_frequency_point_a = 175364;
carrier.ul_absolute_frequency_point_a = 166364;
carrier.nof_prb = 52;
TESTASSERT(bands.get_dl_center_freq(carrier) == 881.5e6);
TESTASSERT(bands.get_ul_center_freq(carrier) == 836.5e6);
// b3
TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.0e6);

@ -368,7 +368,7 @@ int mac_sch_pdu_nr::unpack(const uint8_t* payload, const uint32_t& len)
while (offset < len) {
mac_sch_subpdu_nr sch_pdu(this);
if (sch_pdu.read_subheader(payload + offset) == SRSRAN_ERROR) {
logger.error("Malformed MAC PDU (len=%d, offset=%d)\n", len, offset);
logger.error("Malformed MAC PDU (len=%d, offset=%d)", len, offset);
return SRSRAN_ERROR;
}
offset += sch_pdu.get_total_length();
@ -381,7 +381,7 @@ int mac_sch_pdu_nr::unpack(const uint8_t* payload, const uint32_t& len)
subpdus.push_back(sch_pdu);
}
if (offset != len) {
logger.error("Malformed MAC PDU (len=%d, offset=%d)\n", len, offset);
logger.error("Malformed MAC PDU (len=%d, offset=%d)", len, offset);
return SRSRAN_ERROR;
}

@ -29,7 +29,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb

@ -32,7 +32,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb

@ -662,6 +662,7 @@ uint8_t srsran_band_get_band(uint32_t dl_earfcn)
uint32_t i = SRSRAN_NOF_LTE_BANDS - 1;
if (dl_earfcn > lte_bands[i].dl_earfcn_offset) {
ERROR("Invalid DL_EARFCN=%d", dl_earfcn);
return 0;
}
i--;
while (i > 0 && lte_bands[i].dl_earfcn_offset > dl_earfcn) {
@ -675,6 +676,7 @@ double srsran_band_fd(uint32_t dl_earfcn)
uint32_t i = SRSRAN_NOF_LTE_BANDS - 1;
if (dl_earfcn > lte_bands[i].dl_earfcn_offset) {
ERROR("Invalid DL_EARFCN=%d", dl_earfcn);
return 0;
}
i--;
while (i > 0 && lte_bands[i].dl_earfcn_offset > dl_earfcn) {
@ -688,6 +690,7 @@ double srsran_band_fu(uint32_t ul_earfcn)
uint32_t i = SRSRAN_NOF_LTE_BANDS - 1;
if (ul_earfcn > lte_bands[i].ul_earfcn_offset) {
ERROR("Invalid UL_EARFCN=%d", ul_earfcn);
return 0;
}
i--;
while (i > 0 && (lte_bands[i].ul_earfcn_offset > ul_earfcn || lte_bands[i].ul_earfcn_offset == 0)) {
@ -701,6 +704,7 @@ uint32_t srsran_band_ul_earfcn(uint32_t dl_earfcn)
uint32_t i = SRSRAN_NOF_LTE_BANDS - 1;
if (dl_earfcn > lte_bands[i].dl_earfcn_offset) {
ERROR("Invalid DL_EARFCN=%d", dl_earfcn);
return 0;
}
i--;
while (i > 0 && lte_bands[i].dl_earfcn_offset > dl_earfcn) {

@ -27,7 +27,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb

@ -32,7 +32,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb

@ -34,7 +34,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
6, // nof_prb

@ -31,7 +31,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb

@ -30,7 +30,8 @@
static srsran_carrier_nr_t carrier = {
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb

@ -102,32 +102,33 @@ const char* srsran_rf_get_devname(srsran_rf_t* rf)
int srsran_rf_open_devname(srsran_rf_t* rf, const char* devname, char* args, uint32_t nof_channels)
{
rf->thread_gain_run = false;
/* Try to open the device if name is provided */
if (devname) {
if (devname[0] != '\0') {
int i = 0;
while (available_devices[i] != NULL) {
if (!strcasecmp(available_devices[i]->name, devname)) {
rf->dev = available_devices[i];
return available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels);
}
i++;
// Try to open the device if name is provided
if (devname && devname[0] != '\0') {
int i = 0;
while (available_devices[i] != NULL) {
if (!strcasecmp(available_devices[i]->name, devname)) {
rf->dev = available_devices[i];
return available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels);
}
printf("Device %s not found. Switching to auto mode\n", devname);
i++;
}
}
/* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
int i = 0;
while (available_devices[i] != NULL) {
if (!available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels)) {
rf->dev = available_devices[i];
return 0;
// provided device not found, abort
return SRSRAN_ERROR;
} else {
// auto-mode, try to open in order of apperance in available_devices[] array
int i = 0;
while (available_devices[i] != NULL) {
if (!available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels)) {
rf->dev = available_devices[i];
return SRSRAN_SUCCESS;
}
i++;
}
i++;
}
ERROR("No compatible RF frontend found");
return -1;
return SRSRAN_ERROR;
}
const char* srsran_rf_name(srsran_rf_t* rf)

@ -35,7 +35,7 @@
#include <SoapySDR/Logger.h>
#include <SoapySDR/Time.h>
#include <SoapySDR/Version.h>
#include <Types.h>
#include <SoapySDR/Types.h>
#define HAVE_ASYNC_THREAD 0

@ -713,6 +713,11 @@ 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 = (rsrp_pss + rsrp_sss) / 2.0f;
// avoid taking log of 0 (NaN)
if (rsrp == 0.0) {
rsrp = 1.0;
}
// Compute Noise
float n0_pss = 1e-9; // Almost 0
float n0_sss = 1e-9; // Almost 0

@ -28,7 +28,8 @@
static srsran_carrier_nr_t carrier = {
501, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
52, // nof_prb

@ -37,7 +37,15 @@ void json_formatter::format(detail::log_entry_metadata&& metadata, fmt::memory_b
if (metadata.fmtstring) {
if (metadata.store) {
fmt::basic_format_args<fmt::basic_printf_context_t<char> > args(*metadata.store);
fmt::vprintf(buffer, fmt::to_string_view(metadata.fmtstring), args);
try {
fmt::vprintf(buffer, fmt::to_string_view(metadata.fmtstring), args);
} catch (...) {
fmt::print(stderr, "srsLog error - Invalid format string: \"{}\"\n", metadata.fmtstring);
fmt::format_to(buffer, " -> srsLog error - Invalid format string: \"{}\"", metadata.fmtstring);
#ifdef STOP_ON_WARNING
std::abort();
#endif
}
fmt::format_to(buffer, fmt::to_string_view("\""));
} else {
fmt::format_to(buffer, "{}\"", metadata.fmtstring);
@ -67,7 +75,15 @@ void json_formatter::format_context_begin(const detail::log_entry_metadata& md,
if (md.store) {
fmt::format_to(buffer, " \"log_entry\": \"");
fmt::basic_format_args<fmt::basic_printf_context_t<char> > args(*md.store);
fmt::vprintf(buffer, fmt::to_string_view(md.fmtstring), args);
try {
fmt::vprintf(buffer, fmt::to_string_view(md.fmtstring), args);
} catch (...) {
fmt::print(stderr, "srsLog error - Invalid format string: \"{}\"\n", md.fmtstring);
fmt::format_to(buffer, " -> srsLog error - Invalid format string: \"{}\"", md.fmtstring);
#ifdef STOP_ON_WARNING
std::abort();
#endif
}
fmt::format_to(buffer, "\",\n");
} else {
fmt::format_to(buffer, " \"log_entry\": \"{}\",\n", md.fmtstring);

@ -75,7 +75,15 @@ void text_formatter::format(detail::log_entry_metadata&& metadata, fmt::memory_b
if (metadata.fmtstring) {
if (metadata.store) {
fmt::basic_format_args<fmt::basic_printf_context_t<char> > args(*metadata.store);
fmt::vprintf(buffer, fmt::to_string_view(metadata.fmtstring), args);
try {
fmt::vprintf(buffer, fmt::to_string_view(metadata.fmtstring), args);
} catch (...) {
fmt::print(stderr, "srsLog error - Invalid format string: \"{}\"\n", metadata.fmtstring);
fmt::format_to(buffer, " -> srsLog error - Invalid format string: \"{}\"", metadata.fmtstring);
#ifdef STOP_ON_WARNING
std::abort();
#endif
}
fmt::format_to(buffer, "\n");
} else {
fmt::format_to(buffer, "{}\n", metadata.fmtstring);
@ -115,7 +123,15 @@ void text_formatter::format_context_end(const detail::log_entry_metadata& md,
if (md.store) {
fmt::format_to(buffer, "]: ");
fmt::basic_format_args<fmt::basic_printf_context_t<char> > args(*md.store);
fmt::vprintf(buffer, fmt::to_string_view(md.fmtstring), args);
try {
fmt::vprintf(buffer, fmt::to_string_view(md.fmtstring), args);
} catch (...) {
fmt::print(stderr, "srsLog error - Invalid format string: \"{}\"\n", md.fmtstring);
fmt::format_to(buffer, " -> srsLog error - Invalid format string: \"{}\"", md.fmtstring);
#ifdef STOP_ON_WARNING
std::abort();
#endif
}
fmt::format_to(buffer, "\n");
} else {
fmt::format_to(buffer, "]: {}\n", md.fmtstring);

@ -33,9 +33,10 @@ namespace srslog {
class file_sink : public sink
{
public:
file_sink(std::string name, size_t max_size, std::unique_ptr<log_formatter> f) :
file_sink(std::string name, size_t max_size, bool force_flush, std::unique_ptr<log_formatter> f) :
sink(std::move(f)),
max_size((max_size == 0) ? 0 : std::max<size_t>(max_size, 4 * 1024)),
force_flush(force_flush),
base_filename(std::move(name))
{}
@ -62,6 +63,10 @@ public:
return err_str;
}
if (force_flush) {
flush();
}
return handler.write(buffer);
}
@ -97,6 +102,7 @@ private:
private:
const size_t max_size;
const bool force_flush;
const std::string base_filename;
file_utils::file handler;
size_t current_size = 0;

@ -157,7 +157,10 @@ sink& srslog::fetch_stderr_sink(const std::string& id, std::unique_ptr<log_forma
return *s;
}
sink& srslog::fetch_file_sink(const std::string& path, size_t max_size, std::unique_ptr<log_formatter> f)
sink& srslog::fetch_file_sink(const std::string& path,
size_t max_size,
bool force_flush,
std::unique_ptr<log_formatter> f)
{
assert(!path.empty() && "Empty path string");
@ -170,7 +173,7 @@ sink& srslog::fetch_file_sink(const std::string& path, size_t max_size, std::uni
auto& s = srslog_instance::get().get_sink_repo().emplace(
std::piecewise_construct,
std::forward_as_tuple(path),
std::forward_as_tuple(new file_sink(path, max_size, std::move(f))));
std::forward_as_tuple(new file_sink(path, max_size, force_flush, std::move(f))));
return *s;
}
@ -397,7 +400,8 @@ sink* srslog::create_file_sink(const std::string& path, size_t max_size)
.get_sink_repo()
.emplace(std::piecewise_construct,
std::forward_as_tuple(path),
std::forward_as_tuple(new file_sink(path, max_size, std::unique_ptr<log_formatter>(new text_formatter))))
std::forward_as_tuple(
new file_sink(path, max_size, false, std::unique_ptr<log_formatter>(new text_formatter))))
.get();
}

@ -190,7 +190,7 @@ srslog_sink* srslog_fetch_stderr_sink(void)
return c_cast<srslog_sink>(&fetch_stderr_sink());
}
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size)
srslog_sink* srslog_fetch_file_sink(const char* path, size_t max_size, srslog_bool force_flush)
{
return c_cast<srslog_sink>(&fetch_file_sink(path, max_size));
return c_cast<srslog_sink>(&fetch_file_sink(path, max_size, force_flush));
}

@ -31,7 +31,8 @@
static srsran_carrier_nr_t carrier = {
501, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
0, // dl_absolute_frequency_point_a
0, // ul_absolute_frequency_point_a
0, // offset_to_carrier
srsran_subcarrier_spacing_15kHz, // scs
52, // nof_prb

@ -31,7 +31,7 @@ static constexpr char log_filename[] = "file_sink_test.log";
static bool when_data_is_written_to_file_then_contents_are_valid()
{
file_test_utils::scoped_file_deleter deleter(log_filename);
file_sink file(log_filename, 0, std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy));
file_sink file(log_filename, 0, false, std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy));
std::vector<std::string> entries;
for (unsigned i = 0; i != 10; ++i) {
@ -54,7 +54,7 @@ class file_sink_subclass : public file_sink
{
public:
file_sink_subclass(std::string name, size_t max_size) :
file_sink(std::move(name), max_size, std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy))
file_sink(std::move(name), max_size, false, std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy))
{}
uint32_t get_num_of_files() const { return get_file_index(); }

@ -46,6 +46,7 @@ public:
void stop(){};
private:
void set_metrics_helper(uint32_t num_ue, const mac_metrics_t& mac, const std::vector<phy_metrics_t>& phy);
std::string float_to_string(float f, int digits, int field_width = 6);
std::string float_to_eng_string(float f, int digits);

@ -78,13 +78,20 @@ public:
{
uint32_t ret = 0;
if (cc_idx >= get_nof_carriers()) {
// invalid CC index
return ret;
}
if (cc_idx < cell_list_lte.size()) {
ret = cell_list_lte[cc_idx].cell.nof_prb;
} else if (cc_idx == 1 && !cell_list_nr.empty()) {
// for basic NSA config return width of first NR carrier
ret = cell_list_nr[0].carrier.nof_prb;
} else if (cc_idx >= cell_list_lte.size()) {
// offset CC index by all LTE carriers
cc_idx -= cell_list_lte.size();
if (cc_idx < cell_list_nr.size()) {
ret = cell_list_nr[cc_idx].carrier.nof_prb;
}
}
return ret;
};
uint32_t get_nof_ports(uint32_t cc_idx)

@ -28,7 +28,7 @@
#define SRSRAN_ENB_STACK_LTE_H
#include "mac/mac.h"
#include "mac/mac_nr.h"
#include "mac/nr/mac_nr.h"
#include "rrc/rrc.h"
#include "rrc/rrc_nr.h"
#include "s1ap/s1ap.h"

@ -28,7 +28,7 @@
#define SRSRAN_GNB_STACK_NR_H
#include "s1ap/s1ap.h"
#include "srsenb/hdr/stack/mac/mac_nr.h"
#include "srsenb/hdr/stack/mac/nr/mac_nr.h"
#include "srsenb/hdr/stack/rrc/rrc_nr.h"
#include "srsenb/hdr/stack/upper/pdcp_nr.h"
#include "srsenb/hdr/stack/upper/rlc_nr.h"

@ -59,8 +59,7 @@ public:
void get_metrics(srsenb::mac_metrics_t& metrics);
// MAC interface for RRC
int cell_cfg(const sched_interface::cell_cfg_t& cell,
srsran::const_span<sched_nr_interface::cell_cfg_t> nr_cells) override;
int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) override;
uint16_t reserve_rnti(uint32_t enb_cc_idx) override;
int read_pdu_bcch_bch(uint8_t* payload);
int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) override;
@ -113,10 +112,10 @@ private:
std::atomic<bool> started = {false};
const static uint32_t NUMEROLOGY_IDX = 0; /// only 15kHz supported at this stage
srsran::slot_point pdsch_slot, pusch_slot;
srsenb::sched_nr sched;
srsenb::sched_interface::cell_cfg_t cfg = {};
const static uint32_t NUMEROLOGY_IDX = 0; /// only 15kHz supported at this stage
srsran::slot_point pdsch_slot, pusch_slot;
srsenb::sched_nr sched;
std::vector<sched_nr_interface::cell_cfg_t> cell_config;
// Map of active UEs
pthread_rwlock_t rwlock = {};

@ -50,6 +50,7 @@ public:
int cell_cfg(srsran::const_span<cell_cfg_t> cell_list) override;
void ue_cfg(uint16_t rnti, const ue_cfg_t& cfg) override;
void ue_rem(uint16_t rnti) override;
bool ue_exists(uint16_t rnti) override;
int dl_rach_info(uint32_t cc, const dl_sched_rar_info_t& rar_info);

@ -77,7 +77,7 @@ public:
struct sched_cfg_t {
bool pdsch_enabled = true;
bool pusch_enabled = true;
bool auto_refill_buffer = true;
bool auto_refill_buffer = false;
std::string logger_name = "MAC";
};
@ -128,6 +128,7 @@ public:
virtual int cell_cfg(srsran::const_span<sched_nr_interface::cell_cfg_t> ue_cfg) = 0;
virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0;
virtual void ue_rem(uint16_t rnti) = 0;
virtual bool ue_exists(uint16_t rnti) = 0;
virtual int get_dl_sched(slot_point slot_rx, uint32_t cc, dl_sched_res_t& result) = 0;
virtual int get_ul_sched(slot_point slot_rx, uint32_t cc, ul_sched_t& result) = 0;

@ -27,6 +27,7 @@
#include "srsran/common/block_queue.h"
#include "srsran/common/interfaces_common.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/mac/bsr_nr.h"
#include "srsran/mac/mac_sch_pdu_nr.h"
#include <mutex>
#include <vector>
@ -73,6 +74,9 @@ public:
uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final;
private:
// helper methods
uint32_t buff_size_field_to_bytes(uint32_t buff_size_index, const srsran::bsr_format_nr_t& format);
rlc_interface_mac* rlc = nullptr;
rrc_interface_mac_nr* rrc = nullptr;
phy_interface_stack_nr* phy = nullptr;

@ -136,11 +136,9 @@ public:
int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override;
// rrc_eutra_interface_rrc_nr
void sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) override;
void sgnb_addition_ack(uint16_t eutra_rnti, const sgnb_addition_ack_params_t params) override;
void sgnb_addition_reject(uint16_t eutra_rnti) override;
void sgnb_addition_complete(uint16_t eutra_rnti) override;
void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) override;
// rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override;

@ -38,15 +38,23 @@ namespace srsenb {
class rrc::ue::rrc_endc : public srsran::fsm_t<rrc::ue::rrc_endc>
{
public:
// public events
struct user_crnti_upd_ev {
uint16_t crnti;
uint16_t temp_crnti;
// public events called from EUTRA-RRC
struct sgnb_add_req_sent_ev {};
/// called when 5G RRC accepted new user
struct sgnb_add_req_ack_ev {
sgnb_addition_ack_params_t params;
};
struct ho_cancel_ev {
asn1::s1ap::cause_c cause;
ho_cancel_ev(const asn1::s1ap::cause_c& cause_) : cause(cause_) {}
struct sgnb_add_req_reject_ev {};
/**
* @brief Non-standard event sent from NR-RRC to EUTRA when UE has attached to NR cell
*
* sent after Reconfig complete and contention resolution on NR side
*/
struct sgnb_add_complete_ev {
uint16_t nr_rnti; /// RNTI assigned to UE on NR carrier
};
rrc_endc(srsenb::rrc::ue* outer_ue);
@ -54,17 +62,14 @@ public:
bool fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg);
void handle_eutra_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps);
void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg);
void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15);
void handle_sgnb_addition_reject();
void handle_sgnb_addition_complete();
bool is_endc_supported();
private:
// Send SgNB addition request to gNB
bool start_sgnb_addition();
bool is_endc_activation_running() const { return not is_in_state<idle_st>(); }
bool is_endc_activation_running() const { return not is_in_state<endc_deactivated_st>(); }
rrc::ue* rrc_ue = nullptr;
rrc* rrc_enb = nullptr;
@ -74,51 +79,57 @@ private:
bool endc_supported = false;
asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
// temporary storage for NR reconfiguration
asn1::dyn_octstring nr_secondary_cell_group_cfg_r15;
asn1::dyn_octstring nr_radio_bearer_cfg1_r15;
// fixed ENDC variables
const uint32_t eutra_drb_id = 1; // The DRB ID that converted to NR
const uint32_t lcid_drb_nr = 4;
// events
struct sgnb_add_req_sent_ev {};
struct sgnb_add_req_ack_ev {};
struct sgnb_add_req_reject_ev {};
// internal events
struct rrc_recfg_sent_ev {};
struct prach_nr_received_ev {};
using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s;
using status_transfer_ev = asn1::s1ap::bearers_subject_to_status_transfer_list_l;
// states
struct idle_st {};
struct wait_sgnb_add_req_resp {};
struct prepare_recfg {};
struct wait_recfg_comp {};
struct wait_prach_nr {};
struct endc_deactivated_st {}; // initial state where user is served over EUTRA only
struct wait_sgnb_add_req_resp_st {};
struct prepare_recfg_st {
sgnb_addition_ack_params_t sgnb_config; // Store NR cell group config, etc.
void enter(rrc_endc* f, const sgnb_add_req_ack_ev& ev);
explicit prepare_recfg_st(rrc_endc* parent_);
private:
srslog::basic_logger& logger;
};
struct wait_add_complete_st {}; // user needs to complete RA procedure and send C-RNTI CE
struct endc_activated_st {}; // user has enabled EN-DC successfully and is currently served
// FSM guards
// FSM transition handlers
void handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev);
void handle_sgnb_addition_request_sent(const sgnb_add_req_sent_ev& ev);
void handle_sgnb_add_req_ack(wait_sgnb_add_req_resp_st& s, const sgnb_add_req_ack_ev& ev);
protected:
// states
state_list<idle_st, wait_sgnb_add_req_resp, prepare_recfg, wait_recfg_comp, wait_prach_nr>
states{this, idle_st{}, wait_sgnb_add_req_resp{}, prepare_recfg{}, wait_recfg_comp{}, wait_prach_nr{}};
state_list<endc_deactivated_st, wait_sgnb_add_req_resp_st, prepare_recfg_st, wait_add_complete_st, endc_activated_st>
states{this,
endc_deactivated_st{},
wait_sgnb_add_req_resp_st{},
prepare_recfg_st{this},
wait_add_complete_st{},
endc_activated_st{}};
// transitions
using fsm = rrc_endc;
// clang-format off
using transitions = transition_table<
// Start Target Event Action Guard
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< idle_st, wait_sgnb_add_req_resp, sgnb_add_req_sent_ev, nullptr >,
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< wait_sgnb_add_req_resp, prepare_recfg, sgnb_add_req_ack_ev >,
row< wait_sgnb_add_req_resp, idle_st, sgnb_add_req_reject_ev >,
row< prepare_recfg, wait_recfg_comp, rrc_recfg_sent_ev >,
row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
// Start Target Event Action Guard
// +---------------------------+--------------------------+------------------------+------------------------------+-------------------------+
row< endc_deactivated_st, wait_sgnb_add_req_resp_st, sgnb_add_req_sent_ev, nullptr >,
// +---------------------------+--------------------------+------------------------+------------------------------+-------------------------+
row< wait_sgnb_add_req_resp_st, prepare_recfg_st, sgnb_add_req_ack_ev, &fsm::handle_sgnb_add_req_ack >,
row< wait_sgnb_add_req_resp_st, endc_deactivated_st, sgnb_add_req_reject_ev >,
row< prepare_recfg_st, wait_add_complete_st, rrc_recfg_sent_ev >,
row< wait_add_complete_st, endc_activated_st, sgnb_add_complete_ev >
// +---------------------------+--------------------------+------------------------+------------------------------+-------------------------+
>;
// clang-format on
};

@ -90,7 +90,7 @@ public:
void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) final;
// Interface for EUTRA RRC
int sgnb_addition_request(uint16_t rnti);
int sgnb_addition_request(uint16_t rnti, const sgnb_addition_req_params_t& params);
int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response);
// Interfaces for NGAP
@ -108,12 +108,14 @@ public:
void send_connection_setup();
void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg);
int handle_sgnb_addition_request(uint16_t eutra_rnti);
int handle_sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params);
void crnti_ce_received();
// getters
bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; }
bool is_idle() { return state == rrc_nr_state_t::RRC_IDLE; }
bool is_inactive() { return state == rrc_nr_state_t::RRC_INACTIVE; }
bool is_endc() { return endc; }
// setters
@ -138,6 +140,10 @@ public:
asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg;
const uint32_t drb1_lcid = 4;
// NSA specific variables
bool endc = false;
uint16_t eutra_rnti = SRSRAN_INVALID_RNTI;
};
private:

@ -98,3 +98,8 @@ cell_list =
}
// Add here more cells
);
nr_cell_list =
(
// no NR cells
);

@ -750,16 +750,21 @@ int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_)
cqi_report_cnfg.add_field(new parser::field<bool>("simultaneousAckCQI", &rrc_cfg_->cqi_cfg.simultaneousAckCQI));
cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg_->cqi_cfg.sf_mapping, &rrc_cfg_->cqi_cfg.nof_subframes, 1));
/* RRC config section */
parser::section rrc_cnfg("cell_list");
rrc_cnfg.set_optional(&rrc_cfg_->meas_cfg_present);
rrc_cnfg.add_field(new rr_sections::cell_list_section(args_, rrc_cfg_));
// EUTRA RRC and cell config section
parser::section cell_cnfg("cell_list");
cell_cnfg.set_optional(&rrc_cfg_->meas_cfg_present);
cell_cnfg.add_field(new rr_sections::cell_list_section(args_, rrc_cfg_));
// NR RRC and cell config section
parser::section nr_cell_cnfg("nr_cell_list");
nr_cell_cnfg.add_field(new rr_sections::nr_cell_list_section(args_, rrc_cfg_));
// Run parser with two sections
parser p(args_->enb_files.rr_config);
p.add_section(&mac_cnfg);
p.add_section(&phy_cfg_);
p.add_section(&rrc_cnfg);
p.add_section(&cell_cnfg);
p.add_section(&nr_cell_cnfg);
return p.parse();
}
@ -873,15 +878,7 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
HANDLEPARSERCODE(parse_scell_list(cell_cfg, cellroot));
}
std::string type = "lte";
if (cellroot.exists("type")) {
cellroot.lookupValue("type", type);
}
if (type == "lte") {
rrc_cfg->cell_list.push_back(cell_cfg);
} else if (type == "nr") {
rrc_cfg->cell_list_nr.push_back(cell_cfg);
}
rrc_cfg->cell_list.push_back(cell_cfg);
}
// Configuration check
@ -904,12 +901,67 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
return SRSRAN_SUCCESS;
}
static int parse_nr_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
{
for (uint32_t n = 0; n < (uint32_t)root.getLength(); ++n) {
cell_cfg_t cell_cfg = {};
auto& cellroot = root[n];
parse_opt_field(cell_cfg.rf_port, cellroot, "rf_port");
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.pci, cellroot, "pci"));
cell_cfg.pci = cell_cfg.pci % SRSRAN_NOF_NID_NR;
HANDLEPARSERCODE(parse_required_field(cell_cfg.dl_earfcn, cellroot, "dl_arfcn"));
// frequencies get derived from ARFCN
// Add further cell-specific parameters
rrc_cfg->cell_list_nr.push_back(cell_cfg);
}
// Configuration check
for (auto it = rrc_cfg->cell_list_nr.begin(); it != rrc_cfg->cell_list_nr.end(); ++it) {
// check against NR cells
for (auto it2 = it + 1; it2 != rrc_cfg->cell_list_nr.end(); it2++) {
// Check RF port is not repeated
if (it->rf_port == it2->rf_port) {
ERROR("Repeated RF port for multiple cells");
return SRSRAN_ERROR;
}
// Check cell ID is not repeated
if (it->cell_id == it2->cell_id) {
ERROR("Repeated Cell identifier");
return SRSRAN_ERROR;
}
}
// also check RF port against EUTRA cells
for (auto it_eutra = rrc_cfg->cell_list.begin(); it_eutra != rrc_cfg->cell_list.end(); ++it_eutra) {
// Check RF port is not repeated
if (it->rf_port == it_eutra->rf_port) {
ERROR("Repeated RF port for multiple cells");
return SRSRAN_ERROR;
}
}
}
return SRSRAN_SUCCESS;
}
int cell_list_section::parse(libconfig::Setting& root)
{
HANDLEPARSERCODE(parse_cell_list(args, rrc_cfg, root));
return 0;
}
int nr_cell_list_section::parse(libconfig::Setting& root)
{
HANDLEPARSERCODE(parse_nr_cell_list(args, rrc_cfg, root));
return 0;
}
} // namespace rr_sections
namespace enb_conf_sections {
@ -1061,6 +1113,10 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
phy_cell_cfg.dl_freq_hz = cfg.dl_freq_hz;
} else {
phy_cell_cfg.dl_freq_hz = 1e6 * srsran_band_fd(cfg.dl_earfcn);
if (phy_cell_cfg.dl_freq_hz == 0.0) {
ERROR("Couldn't derive DL frequency for EARFCN=%d", cfg.dl_earfcn);
return SRSRAN_ERROR;
}
}
if (cfg.ul_freq_hz > 0) {
@ -1070,6 +1126,10 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
cfg.ul_earfcn = srsran_band_ul_earfcn(cfg.dl_earfcn);
}
phy_cell_cfg.ul_freq_hz = 1e6 * srsran_band_fu(cfg.ul_earfcn);
if (phy_cell_cfg.ul_freq_hz == 0.0) {
ERROR("Couldn't derive UL frequency for EARFCN=%d", cfg.ul_earfcn);
return SRSRAN_ERROR;
}
}
for (auto scell_it = cfg.scell_list.begin(); scell_it != cfg.scell_list.end();) {

@ -84,7 +84,21 @@ public:
int parse(Setting& root) override;
const char* get_name() override { return "meas_cell_list"; }
const char* get_name() override { return "cell_list"; }
private:
rrc_cfg_t* rrc_cfg;
all_args_t* args;
};
class nr_cell_list_section final : public parser::field_itf
{
public:
explicit nr_cell_list_section(all_args_t* all_args_, rrc_cfg_t* rrc_cfg_) : args(all_args_), rrc_cfg(rrc_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "nr_cell_list"; }
private:
rrc_cfg_t* rrc_cfg;

@ -559,7 +559,7 @@ int main(int argc, char* argv[])
: srslog::fetch_file_sink(args.log.filename, fixup_log_file_maxsize(args.log.file_max_size)));
// Alarms log channel creation.
srslog::sink& alarm_sink = srslog::fetch_file_sink(args.general.alarms_filename);
srslog::sink& alarm_sink = srslog::fetch_file_sink(args.general.alarms_filename, 0, true);
srslog::log_channel& alarms_channel = srslog::fetch_log_channel("alarms", alarm_sink, {"ALRM", '\0', false});
alarms_channel.set_enabled(args.general.alarms_log_enable);
@ -582,7 +582,7 @@ int main(int argc, char* argv[])
// Set up the JSON log channel used by metrics and events.
srslog::sink& json_sink =
srslog::fetch_file_sink(args.general.report_json_filename, 0, srslog::create_json_formatter());
srslog::fetch_file_sink(args.general.report_json_filename, 0, false, srslog::create_json_formatter());
srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {});
json_channel.set_enabled(args.general.report_json_enable);

@ -80,62 +80,43 @@ static bool iszero(float x)
return fabsf(x) < 2 * DBL_EPSILON;
}
void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t period_usec)
void metrics_stdout::set_metrics_helper(uint32_t num_ue,
const mac_metrics_t& mac,
const std::vector<phy_metrics_t>& phy)
{
if (!do_print || enb == nullptr) {
return;
}
if (metrics.rf.rf_error) {
fmt::print("RF status: O={}, U={}, L={}\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l);
}
if (metrics.stack.rrc.ues.size() == 0) {
return;
}
if (++n_reports > 10) {
n_reports = 0;
fmt::print("\n");
fmt::print("-------------------DL--------------------|-------------------------UL-------------------------\n");
fmt::print("rnti cqi ri mcs brate ok nok (%) | pusch pucch phr mcs brate ok nok (%) bsr\n");
}
for (size_t i = 0; i < metrics.stack.rrc.ues.size(); i++) {
for (size_t i = 0; i < num_ue; i++) {
// make sure we have stats for MAC and PHY layer too
if (i >= metrics.stack.mac.ues.size() || i >= metrics.phy.size()) {
if (i >= mac.ues.size() || i >= phy.size()) {
break;
}
if (metrics.stack.mac.ues[i].tx_errors > metrics.stack.mac.ues[i].tx_pkts) {
fmt::print("tx caution errors {} > {}\n", metrics.stack.mac.ues[i].tx_errors, metrics.stack.mac.ues[i].tx_pkts);
if (mac.ues[i].tx_errors > mac.ues[i].tx_pkts) {
fmt::print("tx caution errors {} > {}\n", mac.ues[i].tx_errors, mac.ues[i].tx_pkts);
}
if (metrics.stack.mac.ues[i].rx_errors > metrics.stack.mac.ues[i].rx_pkts) {
fmt::print("rx caution errors {} > {}\n", metrics.stack.mac.ues[i].rx_errors, metrics.stack.mac.ues[i].rx_pkts);
if (mac.ues[i].rx_errors > mac.ues[i].rx_pkts) {
fmt::print("rx caution errors {} > {}\n", mac.ues[i].rx_errors, mac.ues[i].rx_pkts);
}
fmt::print("{:>4x}", metrics.stack.mac.ues[i].rnti);
if (not iszero(metrics.stack.mac.ues[i].dl_cqi)) {
fmt::print(" {:>3}", int(metrics.stack.mac.ues[i].dl_cqi));
fmt::print("{:>4x}", mac.ues[i].rnti);
if (not iszero(mac.ues[i].dl_cqi)) {
fmt::print(" {:>3}", int(mac.ues[i].dl_cqi));
} else {
fmt::print(" {:>3.3}", "n/a");
}
fmt::print(" {:>1}", int(metrics.stack.mac.ues[i].dl_ri));
if (not isnan(metrics.phy[i].dl.mcs)) {
fmt::print(" {:>2}", int(metrics.phy[i].dl.mcs));
fmt::print(" {:>1}", int(mac.ues[i].dl_ri));
if (not isnan(phy[i].dl.mcs)) {
fmt::print(" {:>2}", int(phy[i].dl.mcs));
} else {
fmt::print(" {:>2}", 0);
}
if (metrics.stack.mac.ues[i].tx_brate > 0) {
fmt::print(
" {:>6.6}",
float_to_eng_string((float)metrics.stack.mac.ues[i].tx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3), 1));
if (mac.ues[i].tx_brate > 0) {
fmt::print(" {:>6.6}", float_to_eng_string((float)mac.ues[i].tx_brate / (mac.ues[i].nof_tti * 1e-3), 1));
} else {
fmt::print(" {:>6}", 0);
}
fmt::print(" {:>4}", metrics.stack.mac.ues[i].tx_pkts - metrics.stack.mac.ues[i].tx_errors);
fmt::print(" {:>4}", metrics.stack.mac.ues[i].tx_errors);
if (metrics.stack.mac.ues[i].tx_pkts > 0 && metrics.stack.mac.ues[i].tx_errors) {
fmt::print(" {:>3}%", int((float)100 * metrics.stack.mac.ues[i].tx_errors / metrics.stack.mac.ues[i].tx_pkts));
fmt::print(" {:>4}", mac.ues[i].tx_pkts - mac.ues[i].tx_errors);
fmt::print(" {:>4}", mac.ues[i].tx_errors);
if (mac.ues[i].tx_pkts > 0 && mac.ues[i].tx_errors) {
fmt::print(" {:>3}%", int((float)100 * mac.ues[i].tx_errors / mac.ues[i].tx_pkts));
} else {
fmt::print(" {:>3}%", 0);
}
@ -152,44 +133,66 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe
return sinr;
};
if (not isnan(metrics.phy[i].ul.pusch_sinr) and not iszero(metrics.phy[i].ul.pusch_sinr)) {
fmt::print(" {:>5.1f}", clamp_sinr(metrics.phy[i].ul.pusch_sinr));
if (not isnan(phy[i].ul.pusch_sinr) and not iszero(phy[i].ul.pusch_sinr)) {
fmt::print(" {:>5.1f}", clamp_sinr(phy[i].ul.pusch_sinr));
} else {
fmt::print(" {:>5.5}", "n/a");
}
if (not isnan(metrics.phy[i].ul.pucch_sinr) and not iszero(metrics.phy[i].ul.pucch_sinr)) {
fmt::print(" {:>5.1f}", clamp_sinr(metrics.phy[i].ul.pucch_sinr));
if (not isnan(phy[i].ul.pucch_sinr) and not iszero(phy[i].ul.pucch_sinr)) {
fmt::print(" {:>5.1f}", clamp_sinr(phy[i].ul.pucch_sinr));
} else {
fmt::print(" {:>5.5}", "n/a");
}
fmt::print(" {:>3}", int(metrics.stack.mac.ues[i].phr));
if (not isnan(metrics.phy[i].ul.mcs)) {
fmt::print(" {:>2}", int(metrics.phy[i].ul.mcs));
fmt::print(" {:>3}", int(mac.ues[i].phr));
if (not isnan(phy[i].ul.mcs)) {
fmt::print(" {:>2}", int(phy[i].ul.mcs));
} else {
fmt::print(" {:>2}", 0);
}
if (metrics.stack.mac.ues[i].rx_brate > 0) {
fmt::print(
" {:>6.6}",
float_to_eng_string((float)metrics.stack.mac.ues[i].rx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3), 1));
if (mac.ues[i].rx_brate > 0) {
fmt::print(" {:>6.6}", float_to_eng_string((float)mac.ues[i].rx_brate / (mac.ues[i].nof_tti * 1e-3), 1));
} else {
fmt::print(" {:>6}", 0);
}
fmt::print(" {:>4}", metrics.stack.mac.ues[i].rx_pkts - metrics.stack.mac.ues[i].rx_errors);
fmt::print(" {:>4}", metrics.stack.mac.ues[i].rx_errors);
fmt::print(" {:>4}", mac.ues[i].rx_pkts - mac.ues[i].rx_errors);
fmt::print(" {:>4}", mac.ues[i].rx_errors);
if (metrics.stack.mac.ues[i].rx_pkts > 0 && metrics.stack.mac.ues[i].rx_errors > 0) {
fmt::print(" {:>3}%", int((float)100 * metrics.stack.mac.ues[i].rx_errors / metrics.stack.mac.ues[i].rx_pkts));
if (mac.ues[i].rx_pkts > 0 && mac.ues[i].rx_errors > 0) {
fmt::print(" {:>3}%", int((float)100 * mac.ues[i].rx_errors / mac.ues[i].rx_pkts));
} else {
fmt::print(" {:>3}%", 0);
}
fmt::print(" {:>6.6}", float_to_eng_string(metrics.stack.mac.ues[i].ul_buffer, 2));
fmt::print(" {:>6.6}", float_to_eng_string(mac.ues[i].ul_buffer, 2));
fmt::print("\n");
}
}
void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t period_usec)
{
if (!do_print || enb == nullptr) {
return;
}
if (metrics.rf.rf_error) {
fmt::print("RF status: O={}, U={}, L={}\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l);
}
if (metrics.stack.rrc.ues.size() == 0) {
return;
}
if (++n_reports > 10) {
n_reports = 0;
fmt::print("\n");
fmt::print(" -----------------DL----------------|-------------------------UL-------------------------\n");
fmt::print("rnti cqi ri mcs brate ok nok (%) | pusch pucch phr mcs brate ok nok (%) bsr\n");
}
set_metrics_helper(metrics.stack.rrc.ues.size(), metrics.stack.mac, metrics.phy);
}
std::string metrics_stdout::float_to_string(float f, int digits, int field_width)
{
std::ostringstream os;

@ -19,7 +19,7 @@
*
*/
#include "srsenb/hdr/stack/mac/mac_nr.h"
#include "srsenb/hdr/stack/mac/nr/mac_nr.h"
#include "srsenb/test/mac/nr/sched_nr_cfg_generators.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/log_helper.h"
@ -86,21 +86,37 @@ void mac_nr::stop()
}
}
void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics) {}
void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics)
{
srsran::rwlock_read_guard lock(rwlock);
metrics.ues.reserve(ue_db.size());
for (auto& u : ue_db) {
if (not sched.ue_exists(u.first)) {
continue;
}
metrics.ues.emplace_back();
u.second->metrics_read(&metrics.ues.back());
}
metrics.cc_info.resize(detected_rachs.size());
for (unsigned cc = 0, e = detected_rachs.size(); cc != e; ++cc) {
metrics.cc_info[cc].cc_rach_counter = detected_rachs[cc];
metrics.cc_info[cc].pci = (cc < cell_config.size()) ? cell_config[cc].carrier.pci : 0;
}
}
int mac_nr::cell_cfg(const sched_interface::cell_cfg_t& cell,
srsran::const_span<sched_nr_interface::cell_cfg_t> nr_cells)
int mac_nr::cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells)
{
cfg = cell;
cell_config = nr_cells;
sched.cell_cfg(nr_cells);
detected_rachs.resize(nr_cells.size());
// read SIBs from RRC (SIB1 for now only)
for (int i = 0; i < 1 /* srsenb::sched_interface::MAX_SIBS */; i++) {
if (cell.sibs->len > 0) {
// TODO: add flag for SIBs into cell config
if (true) {
sib_info_t sib = {};
sib.index = i;
sib.periodicity = cell.sibs->period_rf;
sib.periodicity = 4; // TODO: read period_rf from config
sib.payload = srsran::make_byte_buffer();
if (sib.payload == nullptr) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);

@ -109,6 +109,11 @@ void sched_nr::ue_rem(uint16_t rnti)
sched_workers->enqueue_event(rnti, [this, rnti]() { ue_db.erase(rnti); });
}
bool sched_nr::ue_exists(uint16_t rnti)
{
return ue_db.contains(rnti);
}
void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg)
{
if (not ue_db.contains(rnti)) {

@ -105,13 +105,20 @@ int ue_nr::process_pdu(srsran::unique_byte_buffer_t pdu)
}
} break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::SHORT_BSR:
logger.info("SHORT_BSR CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::SHORT_TRUNC_BSR: {
srsran::mac_sch_subpdu_nr::lcg_bsr_t sbsr = subpdu.get_sbsr();
uint32_t buffer_size_bytes = buff_size_field_to_bytes(sbsr.buffer_size, srsran::SHORT_BSR);
// FIXME: a UE might send a zero BSR but still needs an UL grant to finish RA procedure
if (buffer_size_bytes == 0) {
buffer_size_bytes++;
}
sched->ul_bsr(rnti, sbsr.lcg_id, buffer_size_bytes);
} break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::LONG_BSR:
logger.info("LONG_BSR CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::SHORT_TRUNC_BSR:
logger.info("SHORT_TRUNC_BSR CE not implemented.");
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::LONG_TRUNC_BSR:
logger.info("LONG_TRUNC_BSR CE not implemented.");
break;
default:
if (subpdu.is_sdu()) {
@ -143,9 +150,9 @@ int ue_nr::generate_pdu(srsran::byte_buffer_t* pdu, uint32_t grant_size)
// Only create PDU if RLC has something to tx
if (pdu_len > 0) {
logger.info("Adding MAC PDU for RNTI=%d", rnti);
logger.debug("Adding MAC PDU for RNTI=%d", rnti);
ue_rlc_buffer->N_bytes = pdu_len;
logger.info(ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes, "Read %d B from RLC", ue_rlc_buffer->N_bytes);
logger.debug(ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes, "Read %d B from RLC", ue_rlc_buffer->N_bytes);
// add to MAC PDU and pack
mac_pdu_dl.add_sdu(lcid, ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes);
@ -219,4 +226,41 @@ void ue_nr::metrics_cnt()
ue_metrics.nof_tti++;
}
/** Converts the buffer size field of a BSR (5 or 8-bit Buffer Size field) into Bytes
* @param buff_size_field The buffer size field contained in the MAC PDU
* @param format The BSR format that determines the buffer size field length
* @return uint32_t The actual buffer size level in Bytes
*/
uint32_t ue_nr::buff_size_field_to_bytes(uint32_t buff_size_index, const srsran::bsr_format_nr_t& format)
{
using namespace srsran;
// early exit
if (buff_size_index == 0) {
return 0;
}
const uint32_t max_offset = 1; // make the reported value bigger than the 2nd biggest
switch (format) {
case SHORT_BSR:
case SHORT_TRUNC_BSR:
if (buff_size_index >= buffer_size_levels_5bit_max_idx) {
return buffer_size_levels_5bit[buffer_size_levels_5bit_max_idx] + max_offset;
} else {
return buffer_size_levels_5bit[buff_size_index];
}
break;
case LONG_BSR:
case LONG_TRUNC_BSR:
if (buff_size_index > buffer_size_levels_8bit_max_idx) {
return buffer_size_levels_8bit[buffer_size_levels_8bit_max_idx] + max_offset;
} else {
return buffer_size_levels_8bit[buff_size_index];
}
break;
}
return 0;
}
} // namespace srsenb

@ -568,12 +568,10 @@ void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_st
EN-DC/NSA helper functions
*******************************************************************************/
void rrc::sgnb_addition_ack(uint16_t eutra_rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
void rrc::sgnb_addition_ack(uint16_t eutra_rnti, sgnb_addition_ack_params_t params)
{
users.at(eutra_rnti)
->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15);
logger.info("Received SgNB addition acknowledgement for rnti=%d", eutra_rnti);
users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_ack_ev{params});
// trigger RRC Reconfiguration to send NR config to UE
users.at(eutra_rnti)->send_connection_reconf();
@ -581,12 +579,14 @@ void rrc::sgnb_addition_ack(uint16_t eutra_rnti,
void rrc::sgnb_addition_reject(uint16_t eutra_rnti)
{
users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_reject();
logger.error("Received SgNB addition reject for rnti=%d", eutra_rnti);
users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_reject_ev{});
}
void rrc::sgnb_addition_complete(uint16_t eutra_rnti)
void rrc::sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti)
{
users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_complete();
logger.info("User rnti=0x%x successfully enabled EN-DC", eutra_rnti);
users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_complete_ev{nr_rnti});
}
/*******************************************************************************

@ -267,19 +267,14 @@ int bearer_cfg_handler::add_erab(uint8_t
}
const rrc_cfg_qci_t& qci_cfg = qci_it->second;
erabs[erab_id].id = erab_id;
erabs[erab_id].lcid = lcid;
erabs[erab_id].qos_params = qos;
erabs[erab_id].address = addr;
erabs[erab_id].teid_out = teid_out;
// perform checks on QCI config
if (addr.length() > 32) {
logger->error("Only addresses with length <= 32 are supported");
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
if (qos.gbr_qos_info_present and not qci_cfg.configured) {
logger->warning("Provided E-RAB id=%d QoS not supported", erab_id);
logger->error("Provided E-RAB id=%d QoS not supported", erab_id);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
@ -289,20 +284,18 @@ int bearer_cfg_handler::add_erab(uint8_t
int16_t pbr_kbps = qci_cfg.lc_cfg.prioritised_bit_rate.to_number();
uint64_t pbr = pbr_kbps < 0 ? std::numeric_limits<uint64_t>::max() : pbr_kbps * 1000u;
if (req_bitrate > pbr) {
logger->warning("Provided E-RAB id=%d QoS not supported (guaranteed bitrates)", erab_id);
logger->error("Provided E-RAB id=%d QoS not supported (guaranteed bitrates)", erab_id);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
}
if (qos.alloc_retention_prio.pre_emption_cap.value == asn1::s1ap::pre_emption_cap_opts::may_trigger_pre_emption and
qos.alloc_retention_prio.prio_level < qci_cfg.lc_cfg.prio) {
logger->warning("Provided E-RAB id=%d QoS not supported (priority %d < %d)",
erab_id,
qos.alloc_retention_prio.prio_level,
qci_cfg.lc_cfg.prio);
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::invalid_qos_combination;
return SRSRAN_ERROR;
}
// Consider ERAB as accepted
erabs[erab_id].id = erab_id;
erabs[erab_id].lcid = lcid;
erabs[erab_id].qos_params = qos;
erabs[erab_id].address = addr;
erabs[erab_id].teid_out = teid_out;
if (not nas_pdu.empty()) {
erab_info_list[erab_id].assign(nas_pdu.begin(), nas_pdu.end());

@ -133,7 +133,7 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
meas_cfg.meas_gap_cfg_present = true;
meas_cfg.meas_gap_cfg.set_setup();
meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16;
} else if (is_in_state<prepare_recfg>()) {
} else if (is_in_state<prepare_recfg_st>()) {
// FIXME: use bearer manager to remove EUTRA DRB
conn_recfg->rr_cfg_ded.drb_to_release_list_present = true;
conn_recfg->rr_cfg_ded.drb_to_release_list.resize(1);
@ -157,13 +157,14 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn
reconf_v1510.nr_cfg_r15.setup().endc_release_and_add_r15 = false;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15_present = true;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15 =
get_state<prepare_recfg_st>()->sgnb_config.nr_secondary_cell_group_cfg_r15;
reconf_v1510.sk_counter_r15_present = true;
reconf_v1510.sk_counter_r15 = 0;
reconf_v1510.nr_radio_bearer_cfg1_r15_present = true;
reconf_v1510.nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15;
reconf_v1510.nr_radio_bearer_cfg1_r15 = get_state<prepare_recfg_st>()->sgnb_config.nr_radio_bearer_cfg1_r15;
// inform FSM
rrc_recfg_sent_ev recfg_sent{};
@ -234,7 +235,7 @@ void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg)
return;
}
if (not is_in_state<idle_st>()) {
if (not is_in_state<endc_deactivated_st>()) {
Info("Received a MeasReport while already enabling ENDC support. Ignoring...");
return;
}
@ -251,45 +252,48 @@ void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg)
return;
}
// Start EN-DC activation
// Start EN-DC activation using EPS bearer of EUTRA DRB1
rrc_nr_interface_rrc::sgnb_addition_req_params_t params = {};
params.eps_bearer_id =
rrc_enb->bearer_manager.get_lcid_bearer(rrc_ue->rnti, drb_to_lcid((lte_drb)eutra_drb_id)).eps_bearer_id;
logger.info("Triggering SgNB addition");
rrc_enb->rrc_nr->sgnb_addition_request(rrc_ue->rnti);
rrc_enb->rrc_nr->sgnb_addition_request(rrc_ue->rnti, params);
sgnb_add_req_sent_ev sgnb_add_req{};
trigger(sgnb_add_req);
}
void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15_,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15_)
{
logger.info("Received SgNB addition acknowledgement for rnti=%d", rrc_ue->rnti);
rrc::ue::rrc_endc::prepare_recfg_st::prepare_recfg_st(rrc_endc* parent_) : logger(parent_->logger) {}
// store received configurations
nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15_;
nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15_;
void rrc::ue::rrc_endc::prepare_recfg_st::enter(rrc_endc* f, const sgnb_add_req_ack_ev& ev)
{
// store SgNB provided config
sgnb_config = ev.params;
logger.debug(nr_secondary_cell_group_cfg_r15.data(),
nr_secondary_cell_group_cfg_r15.size(),
logger.debug(sgnb_config.nr_secondary_cell_group_cfg_r15.data(),
sgnb_config.nr_secondary_cell_group_cfg_r15.size(),
"nr-SecondaryCellGroupConfig-r15:");
logger.debug(nr_radio_bearer_cfg1_r15.data(), nr_radio_bearer_cfg1_r15.size(), "nr-RadioBearerConfig1-r15:");
sgnb_add_req_ack_ev sgnb_add_ack{};
trigger(sgnb_add_ack);
logger.debug(sgnb_config.nr_radio_bearer_cfg1_r15.data(),
sgnb_config.nr_radio_bearer_cfg1_r15.size(),
"nr-RadioBearerConfig1-r15:");
}
void rrc::ue::rrc_endc::handle_sgnb_addition_reject()
// The gNB has accepted the SgNB addition and has already allocated the user and established all bearers
void rrc::ue::rrc_endc::handle_sgnb_add_req_ack(wait_sgnb_add_req_resp_st& s, const sgnb_add_req_ack_ev& ev)
{
logger.error("Received SgNB addition reject for rnti=%d", rrc_ue->rnti);
}
// TODO: copy buffered PDCP data to SeNB
void rrc::ue::rrc_endc::handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev)
{
logger.info("User rnti=0x%x successfully enabled EN-DC", rrc_ue->rnti);
}
// TODO: path update procedure with GTPU modify bearer request (for mode 3A and 3X)
void rrc::ue::rrc_endc::handle_sgnb_addition_complete()
{
logger.info("Received SgNB addition complete for rnti=%d", rrc_ue->rnti);
// delete EPS bearer mapping over EUTRA PDCP
rrc_enb->bearer_manager.remove_eps_bearer(rrc_ue->rnti, ev.params.eps_bearer_id);
// re-register EPS bearer over NR PDCP
rrc_enb->bearer_manager.add_eps_bearer(
ev.params.nr_rnti, ev.params.eps_bearer_id, srsran::srsran_rat_t::nr, lcid_drb_nr);
// change GTPU tunnel RNTI to match NR RNTI
rrc_enb->gtpu->mod_bearer_rnti(rrc_ue->rnti, ev.params.nr_rnti);
}
bool rrc::ue::rrc_endc::is_endc_supported()

@ -195,11 +195,9 @@ int rrc_nr::update_user(uint16_t new_rnti, uint16_t old_rnti)
}
ue* ue_ptr = old_it->second.get();
// Assume that SgNB addition is running
logger.info("Resuming rnti=0x%x RRC connection due to received C-RNTI CE from rnti=0x%x.", old_rnti, new_rnti);
if (ue_ptr->is_connected()) {
rrc_eutra->sgnb_addition_complete(new_rnti);
}
ue_ptr->crnti_ce_received();
return SRSRAN_SUCCESS;
}
@ -222,6 +220,8 @@ void rrc_nr::config_mac()
// Fill MAC scheduler configuration for SIBs
// TODO: use parsed cell NR cfg configuration
std::vector<srsenb::sched_nr_interface::cell_cfg_t> sched_cells_cfg = {srsenb::get_default_cells_cfg(1)};
// FIXME: entire SI configuration, etc needs to be ported to NR
sched_interface::cell_cfg_t cell_cfg;
set_sched_cell_cfg_sib1(&cell_cfg, cfg.sib1);
@ -237,8 +237,8 @@ void rrc_nr::config_mac()
// Copy Cell configuration
cell_cfg.cell = cfg.cell;
// Configure MAC scheduler
mac->cell_cfg(cell_cfg, sched_cells_cfg);
// Configure MAC/scheduler
mac->cell_cfg(sched_cells_cfg);
}
int32_t rrc_nr::generate_sibs()
@ -413,9 +413,9 @@ void rrc_nr::write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) {}
Interface for EUTRA RRC
*******************************************************************************/
int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti)
int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params)
{
task_sched.defer_task([this, eutra_rnti]() {
task_sched.defer_task([this, eutra_rnti, params]() {
// try to allocate new user
uint16_t nr_rnti = mac->reserve_rnti(0);
if (nr_rnti == SRSRAN_INVALID_RNTI) {
@ -436,7 +436,7 @@ int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti)
logger.warning("Unrecognised rnti: 0x%x", nr_rnti);
return;
}
user_it->second->handle_sgnb_addition_request(eutra_rnti);
user_it->second->handle_sgnb_addition_request(eutra_rnti, params);
});
// return straight away
@ -445,6 +445,8 @@ int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti)
int rrc_nr::sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response)
{
// user has completeted the reconfiguration and has acked on 4G side, wait until RA on NR
logger.info("Received Reconfiguration complete for RNTI=0x%x", eutra_rnti);
return SRSRAN_SUCCESS;
}
@ -1094,7 +1096,7 @@ int rrc_nr::ue::pack_nr_radio_bearer_config(asn1::dyn_octstring& packed_nr_beare
sec_cfg.key_to_use_present = true;
sec_cfg.key_to_use = asn1::rrc_nr::security_cfg_s::key_to_use_opts::secondary;
sec_cfg.security_algorithm_cfg_present = true;
sec_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_opts::nea2;
sec_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_opts::nea0;
// pack it
packed_nr_bearer_config.resize(128);
@ -1110,36 +1112,50 @@ int rrc_nr::ue::pack_nr_radio_bearer_config(asn1::dyn_octstring& packed_nr_beare
return SRSRAN_SUCCESS;
}
int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti)
int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti_, const sgnb_addition_req_params_t& req_params)
{
// Add DRB1 to RLC and PDCP
if (add_drb() != SRSRAN_SUCCESS) {
parent->logger.error("Failed to configure DRB");
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti);
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti_);
return SRSRAN_ERROR;
}
// provide hard-coded NR configs
asn1::dyn_octstring nr_secondary_cell_group_cfg;
if (pack_rrc_reconfiguraiton(nr_secondary_cell_group_cfg) == SRSRAN_ERROR) {
rrc_eutra_interface_rrc_nr::sgnb_addition_ack_params_t ack_params = {};
if (pack_rrc_reconfiguraiton(ack_params.nr_secondary_cell_group_cfg_r15) == SRSRAN_ERROR) {
parent->logger.error("Failed to pack RRC Reconfiguration. Sending SgNB addition reject.");
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti);
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti_);
return SRSRAN_ERROR;
}
asn1::dyn_octstring radio_bearer_config_buffer;
if (pack_nr_radio_bearer_config(radio_bearer_config_buffer) == SRSRAN_ERROR) {
if (pack_nr_radio_bearer_config(ack_params.nr_radio_bearer_cfg1_r15) == SRSRAN_ERROR) {
parent->logger.error("Failed to pack NR radio bearer config. Sending SgNB addition reject.");
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti);
parent->rrc_eutra->sgnb_addition_reject(eutra_rnti_);
return SRSRAN_ERROR;
}
// send response to EUTRA
parent->rrc_eutra->sgnb_addition_ack(eutra_rnti, nr_secondary_cell_group_cfg, radio_bearer_config_buffer);
ack_params.nr_rnti = rnti;
ack_params.eps_bearer_id = req_params.eps_bearer_id;
parent->rrc_eutra->sgnb_addition_ack(eutra_rnti_, ack_params);
// recognize RNTI as ENDC user
endc = true;
eutra_rnti = eutra_rnti_;
return SRSRAN_SUCCESS;
}
void rrc_nr::ue::crnti_ce_received()
{
// Assume NSA mode active
if (endc) {
// send SgNB addition complete for ENDC users
parent->rrc_eutra->sgnb_addition_complete(eutra_rnti, rnti);
}
}
/**
* @brief Set DRB configuration
*

@ -405,7 +405,7 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu)
} else {
parent->logger.warning("Received MeasReport but no mobility configuration is available");
}
if (endc_handler) {
if (endc_handler != nullptr) {
endc_handler->handle_ue_meas_report(ul_dcch_msg.msg.c1().meas_report());
}
break;
@ -1018,7 +1018,7 @@ int rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg)
parent->logger.info("UE rnti: 0x%x category: %d", rnti, eutra_capabilities.ue_category);
if (endc_handler) {
if (endc_handler != nullptr) {
endc_handler->handle_eutra_capabilities(eutra_capabilities);
}
}
@ -1172,11 +1172,13 @@ int rrc::ue::setup_erab(uint16_t erab_
return SRSRAN_ERROR;
}
if (bearer_list.add_erab(erab_id, qos_params, addr, gtpu_teid_out, nas_pdu, cause) != SRSRAN_SUCCESS) {
parent->logger.error("Couldn't add E-RAB id=%d for rnti=0x%x", erab_id, rnti);
return SRSRAN_ERROR;
}
if (bearer_list.add_gtpu_bearer(erab_id) != SRSRAN_SUCCESS) {
cause.set_radio_network().value = asn1::s1ap::cause_radio_network_opts::radio_res_not_available;
bearer_list.release_erab(erab_id);
parent->logger.error("Couldn't add E-RAB id=%d for rnti=0x%x", erab_id, rnti);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;

@ -47,12 +47,7 @@ public:
class mac_nr_dummy : public mac_interface_rrc_nr
{
public:
int cell_cfg(const sched_interface::cell_cfg_t& cell,
srsran::const_span<sched_nr_interface::cell_cfg_t> nr_cells) override
{
cellcfgobj = cell;
return SRSRAN_SUCCESS;
}
int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) override { return SRSRAN_SUCCESS; }
uint16_t reserve_rnti(uint32_t enb_cc_idx) override { return 0x4601; }
int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) override { return SRSRAN_SUCCESS; }

@ -92,6 +92,8 @@ void sched_nr_cfg_serialized_test()
task_job_manager tasks;
sched_nr_interface::sched_cfg_t cfg;
cfg.auto_refill_buffer = true;
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
sched_nr_sim_base sched_tester(cfg, cells_cfg, "Serialized Test");
@ -140,7 +142,9 @@ void sched_nr_cfg_parallel_cc_test()
uint32_t max_nof_ttis = 1000;
task_job_manager tasks;
sched_nr_interface::sched_cfg_t cfg;
sched_nr_interface::sched_cfg_t cfg;
cfg.auto_refill_buffer = true;
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
sched_nr_sim_base sched_tester(cfg, cells_cfg, "Parallel CC Test");

@ -102,7 +102,8 @@ int test_rrc_setup()
int main()
{
TESTASSERT(srsenb::test_sib_generation() == SRSRAN_SUCCESS);
// FIXME: disabled temporarily until SIB generation is fixed
// TESTASSERT(srsenb::test_sib_generation() == SRSRAN_SUCCESS);
TESTASSERT(srsenb::test_rrc_setup() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;

@ -33,7 +33,7 @@
#include "srsran/interfaces/epc_interfaces.h"
#include "srsran/srslog/srslog.h"
#include <cstddef>
#include <fstream>
#include <map>
#define LTE_FDD_ENB_IND_HE_N_BITS 5
@ -103,7 +103,6 @@ private:
void resync_sqn_milenage(hss_ue_ctx_t* ue_ctx, uint8_t* auts);
void resync_sqn_xor(hss_ue_ctx_t* ue_ctx, uint8_t* auts);
std::vector<std::string> split_string(const std::string& str, char delimiter);
void get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len);
void increment_ue_sqn(hss_ue_ctx_t* ue_ctx);

@ -20,6 +20,7 @@
*/
#include "srsepc/hdr/hss/hss.h"
#include "srsran/common/security.h"
#include "srsran/common/string_helpers.h"
#include <arpa/inet.h>
#include <inttypes.h> // for printing uint64_t
#include <iomanip>
@ -103,7 +104,7 @@ bool hss::read_db_file(std::string db_filename)
while (std::getline(m_db_file, line)) {
if (line[0] != '#' && line.length() > 0) {
uint column_size = 10;
std::vector<std::string> split = split_string(line, ',');
std::vector<std::string> split = srsran::split_string(line, ',');
if (split.size() != column_size) {
m_logger.error("Error parsing UE database. Wrong number of columns in .csv");
m_logger.error("Columns: %zd, Expected %d.", split.size(), column_size);
@ -124,20 +125,20 @@ bool hss::read_db_file(std::string db_filename)
return false;
}
ue_ctx->imsi = strtoull(split[2].c_str(), nullptr, 10);
get_uint_vec_from_hex_str(split[3], ue_ctx->key, 16);
srsran::get_uint_vec_from_hex_str(split[3], ue_ctx->key, 16);
if (split[4] == std::string("op")) {
ue_ctx->op_configured = true;
get_uint_vec_from_hex_str(split[5], ue_ctx->op, 16);
srsran::get_uint_vec_from_hex_str(split[5], ue_ctx->op, 16);
srsran::compute_opc(ue_ctx->key, ue_ctx->op, ue_ctx->opc);
} else if (split[4] == std::string("opc")) {
ue_ctx->op_configured = false;
get_uint_vec_from_hex_str(split[5], ue_ctx->opc, 16);
srsran::get_uint_vec_from_hex_str(split[5], ue_ctx->opc, 16);
} else {
m_logger.error("Neither OP nor OPc configured.");
return false;
}
get_uint_vec_from_hex_str(split[6], ue_ctx->amf, 2);
get_uint_vec_from_hex_str(split[7], ue_ctx->sqn, 6);
srsran::get_uint_vec_from_hex_str(split[6], ue_ctx->amf, 2);
srsran::get_uint_vec_from_hex_str(split[7], ue_ctx->sqn, 6);
m_logger.debug("Added user from DB, IMSI: %015" PRIu64 "", ue_ctx->imsi);
m_logger.debug(ue_ctx->key, 16, "User Key : ");
@ -223,19 +224,19 @@ bool hss::write_db_file(std::string db_filename)
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << srsran::hex_string(it->second->key, 16);
m_db_file << ",";
if (it->second->op_configured) {
m_db_file << "op,";
m_db_file << hex_string(it->second->op, 16);
m_db_file << srsran::hex_string(it->second->op, 16);
} else {
m_db_file << "opc,";
m_db_file << hex_string(it->second->opc, 16);
m_db_file << srsran::hex_string(it->second->opc, 16);
}
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << srsran::hex_string(it->second->amf, 2);
m_db_file << ",";
m_db_file << hex_string(it->second->sqn, 6);
m_db_file << srsran::hex_string(it->second->sqn, 6);
m_db_file << ",";
m_db_file << it->second->qci;
if (it->second->static_ip_addr != "0.0.0.0") {
@ -620,41 +621,6 @@ hss_ue_ctx_t* hss::get_ue_ctx(uint64_t imsi)
return ue_ctx_it->second.get();
}
/* Helper functions*/
std::vector<std::string> hss::split_string(const std::string& str, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
void hss::get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len)
{
const char* pos = key_str.c_str();
for (uint count = 0; count < len; count++) {
sscanf(pos, "%2hhx", &key[count]);
pos += 2;
}
return;
}
std::string hss::hex_string(uint8_t* hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < size; i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
std::map<std::string, uint64_t> hss::get_ip_to_imsi(void) const
{
return m_ip_to_imsi;

@ -99,8 +99,6 @@ public:
/// Semaphore for aligning UL work
srsran::tti_semaphore<void*> dl_ul_semaphore;
srsran_slot_cfg_t rar_grant_slot = {};
state()
{
// Hard-coded values, this should be set when the measurements take place

@ -50,7 +50,8 @@ public:
const int preamble_index,
const float preamble_received_target_power,
const float ta_base_sec = 0.0f) override;
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> array,
int set_ul_grant(uint32_t rx_tti,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> array,
uint16_t rnti,
srsran_rnti_type_t rnti_type) override;
bool set_config(const srsran::phy_cfg_nr_t& cfg) override;

@ -174,7 +174,8 @@ public:
int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_) final;
bool set_config(const srsran::phy_cfg_nr_t& cfg) final;
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
int set_ul_grant(uint32_t rx_tti,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
uint16_t rnti,
srsran_rnti_type_t rnti_type) final;
void send_prach(const uint32_t prach_occasion,

@ -56,7 +56,7 @@ public:
srsran::unique_byte_buffer_t get_pdu(uint32_t max_pdu_len);
// Interface for BSR procedure
void generate_bsr_mac_ce(const bsr_interface_mux_nr::bsr_format_nr_t& format);
void generate_bsr_mac_ce(const srsran::bsr_format_nr_t& format);
private:
// internal helper methods

@ -27,6 +27,7 @@
#include "proc_sr_nr.h"
#include "srsran/common/task_scheduler.h"
#include "srsran/mac/bsr_nr.h"
#include "srsran/mac/mac_sch_pdu_nr.h"
#include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_common/mac_common.h"
@ -41,9 +42,6 @@ class rlc_interface_mac;
class bsr_interface_mux_nr
{
public:
// TS 38.321 Sec 6.1.3.1
typedef enum { SHORT_BSR, LONG_BSR, SHORT_TRUNC_BSR, LONG_TRUNC_BSR } bsr_format_nr_t;
/// MUX calls BSR to receive the buffer state of a single LCG.
virtual srsran::mac_sch_subpdu_nr::lcg_bsr_t generate_sbsr() = 0;
};
@ -52,7 +50,7 @@ class mux_interface_bsr_nr
{
public:
/// Inform MUX unit to that a BSR needs to be generated in the next UL transmission.
virtual void generate_bsr_mac_ce(const bsr_interface_mux_nr::bsr_format_nr_t& format) = 0;
virtual void generate_bsr_mac_ce(const srsran::bsr_format_nr_t& format) = 0;
};
/**
@ -110,7 +108,7 @@ private:
bool check_new_data(const mac_buffer_states_t& new_buffer_state);
bool check_any_channel();
uint8_t buff_size_bytes_to_field(uint32_t buffer_size, bsr_format_nr_t format);
uint8_t buff_size_bytes_to_field(uint32_t buffer_size, srsran::bsr_format_nr_t format);
uint32_t find_max_priority_lcg_with_data();

@ -73,6 +73,7 @@ private:
int ra_window_length = -1, ra_window_start = -1;
uint16_t rar_rnti = SRSRAN_INVALID_RNTI;
uint16_t temp_crnti = SRSRAN_INVALID_RNTI;
std::mutex mutex;
srsran::rach_nr_cfg_t rach_cfg = {};
bool configured = false;

@ -22,10 +22,11 @@
#ifndef SRSUE_PROC_SR_NR_H
#define SRSUE_PROC_SR_NR_H
#include "srsue/hdr/stack/mac_nr/mac_nr_interfaces.h"
#include "srsran/interfaces/ue_mac_interfaces.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_nr/mac_nr_interfaces.h"
#include <mutex>
#include <stdint.h>
/// Scheduling Request procedure as defined in 5.4.4 of 38.321
@ -48,6 +49,7 @@ public:
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx);
private:
void reset_unsafe();
int sr_counter = 0;
bool is_pending_sr = false;
@ -58,7 +60,8 @@ private:
phy_interface_mac_nr* phy = nullptr;
srslog::basic_logger& logger;
bool initiated = false;
bool initiated = false;
std::mutex mutex;
};
} // namespace srsue

@ -392,6 +392,7 @@ private:
void add_srb(const asn1::rrc::srb_to_add_mod_s& srb_cnfg);
void add_drb(const asn1::rrc::drb_to_add_mod_s& drb_cnfg);
void release_drb(uint32_t drb_id);
uint32_t get_lcid_for_drb_id(const uint32_t& drb_id);
uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id);
uint32_t get_drb_id_for_eps_bearer(const uint32_t& eps_bearer_id);
uint32_t get_eps_bearer_id_for_drb_id(const uint32_t& drb_id);

@ -51,7 +51,6 @@ struct rrc_nr_args_t {
core_less_args_t coreless;
uint32_t sim_nr_meas_pci;
bool pdcp_short_sn_support;
bool skip_rar;
std::string supported_bands_nr_str;
std::vector<uint32_t> supported_bands_nr;
std::vector<uint32_t> supported_bands_eutra;

@ -267,20 +267,6 @@ private:
return true;
}
std::vector<uint8_t> split_string(const std::string input)
{
std::vector<uint8_t> list;
std::stringstream ss(input);
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
if (not substr.empty()) {
list.push_back(strtol(substr.c_str(), nullptr, 10));
}
}
return list;
}
// NAS Idle procedures
class plmn_search_proc; // PLMN selection proc (fwd declared)

@ -141,7 +141,6 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("rrc.mbms_service_port", bpo::value<uint32_t>(&args->stack.rrc.mbms_service_port)->default_value(4321), "Port of the MBMS service")
("rrc.nr_measurement_pci", bpo::value<uint32_t>(&args->stack.rrc_nr.sim_nr_meas_pci)->default_value(500), "NR PCI for the simulated NR measurement")
("rrc.nr_short_sn_support", bpo::value<bool>(&args->stack.rrc_nr.pdcp_short_sn_support)->default_value(true), "Announce PDCP short SN support")
("rrc.skip_nr_rar", bpo::value<bool>(&args->stack.rrc_nr.skip_rar)->default_value(false), "Whether to skip RAR reception (temporary feature)")
("nas.apn", bpo::value<string>(&args->stack.nas.apn_name)->default_value(""), "Set Access Point Name (APN) for data services")
("nas.apn_protocol", bpo::value<string>(&args->stack.nas.apn_protocol)->default_value(""), "Set Access Point Name (APN) protocol for data services")
@ -735,7 +734,7 @@ int main(int argc, char* argv[])
// Set up the JSON log channel used by metrics.
srslog::sink& json_sink =
srslog::fetch_file_sink(args.general.metrics_json_filename, 0, srslog::create_json_formatter());
srslog::fetch_file_sink(args.general.metrics_json_filename, 0, false, srslog::create_json_formatter());
srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {});
json_channel.set_enabled(args.general.metrics_json_enable);

@ -94,7 +94,7 @@ bool cc_worker::update_cfg()
}
double abs_freq_point_a_freq =
srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_point_a);
srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.dl_absolute_frequency_point_a);
double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_ssb);
double carrier_center_freq =
@ -303,7 +303,7 @@ bool cc_worker::decode_pdsch_dl()
str_extra.data());
} else {
logger.info(pdsch_res.tb[0].payload,
pdsch_cfg.grant.tb[0].tbs / 8,
pdsch_res.tb[0].crc ? pdsch_cfg.grant.tb[0].tbs / 8 : 0,
"PDSCH: cc=%d pid=%d %s ack_tti_tx=%d",
cc_idx,
pid,
@ -345,14 +345,11 @@ bool cc_worker::decode_pdsch_dl()
// Notify MAC about PDSCH decoding result
mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {};
mac_dl_result.ack = pdsch_res.tb[0].crc;
mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful
mac_dl_result.rx_slot_idx = dl_slot_cfg.idx; // Rx TTI for this TB (required for correct Msg3 timing)
mac_dl_result.ack = pdsch_res.tb[0].crc;
mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful
phy.stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result));
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) {
phy.rar_grant_slot = dl_slot_cfg;
}
if (pdsch_res.tb[0].crc) {
// Generate DL metrics
dl_metrics_t dl_m = {};

@ -108,7 +108,9 @@ void worker_pool::send_prach(const uint32_t prach_occasion,
prach_buffer->prepare_to_send(preamble_index);
}
int worker_pool::set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
// called from Stack thread when processing RAR PDU
int worker_pool::set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
uint16_t rnti,
srsran_rnti_type_t rnti_type)
{
@ -122,21 +124,24 @@ int worker_pool::set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> pac
srsran_vec_u8_copy(dci_msg.payload, packed_ul_grant.data(), SRSRAN_RAR_UL_GRANT_NBITS);
srsran_dci_ul_nr_t dci_ul = {};
if (srsran_dci_nr_ul_unpack(NULL, &dci_msg, &dci_ul) < SRSRAN_SUCCESS) {
logger.error("Couldn't unpack UL grant");
return SRSRAN_ERROR;
}
// initialize with Rx TTI of RAR
srsran_slot_cfg_t msg3_slot_cfg = {};
msg3_slot_cfg.idx = rar_slot_idx;
if (logger.info.enabled()) {
std::array<char, 512> str;
srsran_dci_nr_t dci = {};
srsran_dci_ul_nr_to_str(&dci, &dci_ul, str.data(), str.size());
logger.set_context(phy_state.rar_grant_slot.idx);
logger.set_context(msg3_slot_cfg.idx);
logger.info("Setting RAR Grant: %s", str.data());
}
phy_state.set_ul_pending_grant(phy_state.rar_grant_slot, dci_ul);
phy_state.set_ul_pending_grant(msg3_slot_cfg, dci_ul);
return SRSRAN_SUCCESS;
}
@ -145,7 +150,7 @@ bool worker_pool::set_config(const srsran::phy_cfg_nr_t& cfg)
phy_state.cfg = cfg;
logger.info(
"Setting new PHY configuration ARFCN=%d, PCI=%d", cfg.carrier.absolute_frequency_point_a, cfg.carrier.pci);
"Setting new PHY configuration ARFCN=%d, PCI=%d", cfg.carrier.dl_absolute_frequency_point_a, cfg.carrier.pci);
// Set carrier information
info_metrics_t info = {};
@ -200,6 +205,7 @@ void worker_pool::get_metrics(phy_metrics_t& m)
{
phy_state.get_metrics(m);
}
int worker_pool::tx_request(const phy_interface_mac_nr::tx_request_t& request)
{
return 0;

@ -631,11 +631,12 @@ int phy::init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran
return SRSRAN_SUCCESS;
}
int phy::set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
int phy::set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
uint16_t rnti,
srsran_rnti_type_t rnti_type)
{
return nr_workers.set_ul_grant(packed_ul_grant, rnti, rnti_type);
return nr_workers.set_ul_grant(rar_slot_idx, packed_ul_grant, rnti, rnti_type);
}
void phy::send_prach(const uint32_t prach_occasion,
@ -658,20 +659,16 @@ void phy::set_earfcn(std::vector<uint32_t> earfcns)
bool phy::set_config(const srsran::phy_cfg_nr_t& cfg)
{
// Derive actual RF frequencies for NR carrier
double abs_freq_point_a_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(cfg.carrier.absolute_frequency_point_a);
// for FR1 unit of resources blocks for freq calc is always 180kHz regardless for actual SCS of carrier
// TODO: add offset_to_carrier
double carrier_center_freq =
abs_freq_point_a_freq +
(cfg.carrier.nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(srsran_subcarrier_spacing_t::srsran_subcarrier_spacing_15kHz) *
SRSRAN_NRE);
srsran::srsran_band_helper band_helper;
double dl_freq_hz = band_helper.get_dl_center_freq(cfg.carrier);
double ul_freq_hz = band_helper.get_ul_center_freq(cfg.carrier);
// tune radio
for (uint32_t i = 0; i < common.args->nof_nr_carriers; i++) {
logger_phy.info("Tuning channel %d to %.2f GHz", i + common.args->nof_lte_carriers, carrier_center_freq / 1e6);
radio->set_rx_freq(i + common.args->nof_lte_carriers, carrier_center_freq);
radio->set_tx_freq(i + common.args->nof_lte_carriers, carrier_center_freq);
logger_phy.info("Tuning Rx channel %d to %.2f GHz", i + common.args->nof_lte_carriers, dl_freq_hz / 1e6);
radio->set_rx_freq(i + common.args->nof_lte_carriers, dl_freq_hz);
logger_phy.info("Tuning Tx channel %d to %.2f GHz", i + common.args->nof_lte_carriers, ul_freq_hz / 1e6);
radio->set_tx_freq(i + common.args->nof_lte_carriers, ul_freq_hz);
}
return nr_workers.set_config(cfg);

@ -179,13 +179,13 @@ bool mux_nr::msg3_is_empty()
return msg3_buff->N_bytes == 0;
}
void mux_nr::generate_bsr_mac_ce(const bsr_interface_mux_nr::bsr_format_nr_t& format)
void mux_nr::generate_bsr_mac_ce(const srsran::bsr_format_nr_t& format)
{
switch (format) {
case bsr_interface_mux_nr::SHORT_BSR:
case srsran::SHORT_BSR:
add_bsr_ce = sbsr_ce;
break;
case bsr_interface_mux_nr::LONG_BSR:
case srsran::LONG_BSR:
add_bsr_ce = lbsr_ce;
default:
logger.error("MUX can only be instructred to generate short or long BSRs.");

@ -25,67 +25,7 @@
namespace srsue {
// TS 38.321, Table 6.1.3.1-1 Buffer size levels (in bytes) for 5-bit Buffer Size field, all values <= except marked
static const uint32_t buffer_size_levels_5bit_max_idx = 31;
static uint32_t buffer_size_levels_5bit[buffer_size_levels_5bit_max_idx + 1] = {
/* == */ 0, 10, 14, 20, 28, 38, 53, 74, 102, 142, 198,
276, 384, 535, 745, 1038, 1446, 2014, 2806, 3909, 5446, 7587,
10570, 14726, 20516, 28581, 39818, 55474, 77284, 107669, 150000, /* > */ 150000};
// TS 38.321, Table 6.1.3.1-2: Buffer size levels (in bytes) for 8-bit Buffer Size field, all values <= except marked
static const uint32_t buffer_size_levels_8bit_max_idx = 254;
static uint32_t buffer_size_levels_8bit[buffer_size_levels_8bit_max_idx + 1] = {
/* == */ 0, 10, 11, 12, 13,
14, 15, 16, 17, 18,
19, 20, 22, 23, 25,
26, 28, 30, 32, 34,
36, 38, 40, 43, 46,
49, 52, 55, 59, 62,
66, 71, 75, 80, 85,
91, 97, 103, 110, 117,
124, 132, 141, 150, 160,
170, 181, 193, 205, 218,
233, 248, 264, 281, 299,
318, 339, 361, 384, 409,
436, 464, 494, 526, 560,
597, 635, 677, 720, 767,
817, 870, 926, 987, 1051,
1119, 1191, 1269, 1351, 1439,
1532, 1631, 1737, 1850, 1970,
2098, 2234, 2379, 2533, 2698,
2873, 3059, 3258, 3469, 3694,
3934, 4189, 4461, 4751, 5059,
5387, 5737, 6109, 6506, 6928,
7378, 7857, 8367, 8910, 9488,
10104, 10760, 11458, 12202, 12994,
13838, 14736, 15692, 16711, 17795,
18951, 20181, 21491, 22885, 24371,
25953, 27638, 29431, 31342, 33376,
35543, 37850, 40307, 42923, 45709,
48676, 51836, 55200, 58784, 62599,
66663, 70990, 75598, 80505, 85730,
91295, 97221, 103532, 110252, 117409,
125030, 133146, 141789, 150992, 160793,
171231, 182345, 194182, 206786, 220209,
234503, 249725, 265935, 283197, 301579,
321155, 342002, 364202, 387842, 413018,
439827, 468377, 498780, 531156, 565634,
602350, 641449, 683087, 727427, 774645,
824928, 878475, 935498, 996222, 1060888,
1129752, 1203085, 1281179, 1364342, 1452903,
1547213, 1647644, 1754595, 1868488, 1989774,
2118933, 2256475, 2402946, 2558924, 2725027,
2901912, 3090279, 3290873, 3504487, 3731968,
3974215, 4232186, 4506902, 4799451, 5110989,
5442750, 5796046, 6172275, 6572925, 6999582,
7453933, 7937777, 8453028, 9001725, 9586039,
10208280, 10870913, 11576557, 12328006, 13128233,
13980403, 14887889, 15854280, 16883401, 17979324,
19146385, 20389201, 21712690, 23122088, 24622972,
26221280, 27923336, 29735875, 31666069, 33721553,
35910462, 38241455, 40723756, 43367187, 46182206,
49179951, 52372284, 55771835, 59392055, 63247269,
67352729, 71724679, 76380419, 81338368, /* > */ 81338368};
using namespace srsran;
int32_t proc_bsr_nr::init(proc_sr_nr* sr_,
mux_interface_bsr_nr* mux_,
@ -205,8 +145,15 @@ bool proc_bsr_nr::check_new_data(const mac_buffer_states_t& new_buffer_state)
return false;
}
/**
* @brief Called by Mux through PHY worker whenever a new SBSR CE
* needs to be included in a MAC PDU.
*
* @return SBSR CE for subPDU containing the buffer state of the highest priority LCG
*/
srsran::mac_sch_subpdu_nr::lcg_bsr_t proc_bsr_nr::generate_sbsr()
{
std::lock_guard<std::mutex> lock(mutex);
srsran::mac_sch_subpdu_nr::lcg_bsr_t sbsr = {};
if (buffer_state.nof_lcgs_with_data > 0) {
sbsr.lcg_id = buffer_state.last_non_zero_lcg;

@ -123,11 +123,13 @@ bool proc_ra_nr::has_rar_rnti()
bool proc_ra_nr::has_temp_crnti()
{
std::lock_guard<std::mutex> lock(mutex);
return temp_crnti != SRSRAN_INVALID_RNTI;
}
uint16_t proc_ra_nr::get_temp_crnti()
{
std::lock_guard<std::mutex> lock(mutex);
return temp_crnti;
}
@ -189,6 +191,7 @@ void proc_ra_nr::ra_preamble_transmission()
// 5.1.4 Random Access Preamble transmission
void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb)
{
std::lock_guard<std::mutex> lock(mutex);
if (state != WAITING_FOR_RESPONSE_RECEPTION) {
logger.warning(
"Wrong state for ra reponse reception %s (expected state %s)",
@ -216,7 +219,7 @@ void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::tb_action_dl_
temp_crnti = subpdu.get_temp_crnti();
// Set Temporary-C-RNTI if provided, otherwise C-RNTI is ok
phy->set_ul_grant(subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra);
phy->set_ul_grant(tb.rx_slot_idx, subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra);
// reset all parameters that are used before rar
rar_rnti = SRSRAN_INVALID_RNTI;
@ -274,6 +277,7 @@ void proc_ra_nr::ra_contention_resolution(uint64_t rx_contention_id)
void proc_ra_nr::ra_completion()
{
std::lock_guard<std::mutex> lock(mutex);
if (state != WAITING_FOR_COMPLETION) {
logger.warning("Wrong state for ra completion by phy %s (expected state %s)",
srsran::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
@ -288,6 +292,7 @@ void proc_ra_nr::ra_completion()
void proc_ra_nr::ra_error()
{
std::lock_guard<std::mutex> lock(mutex);
temp_crnti = SRSRAN_INVALID_RNTI;
preamble_transmission_counter++;
contention_resolution_timer.stop();
@ -356,12 +361,6 @@ void proc_ra_nr::prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t
ra_window_start = TTI_ADD(tti, 3);
logger.debug("Calculated ra_window_start=%d, ra_window_length=%d", ra_window_start, ra_window_length);
state = WAITING_FOR_RESPONSE_RECEPTION;
if (rach_cfg.skip_rar) {
// temp hack for NSA eNB development
state = WAITING_FOR_COMPLETION;
ra_completion();
}
});
}

@ -30,6 +30,7 @@ proc_sr_nr::proc_sr_nr(srslog::basic_logger& logger) : logger(logger) {}
int32_t proc_sr_nr::init(mac_interface_sr_nr* mac_, phy_interface_mac_nr* phy_, rrc_interface_mac* rrc_)
{
std::lock_guard<std::mutex> lock(mutex);
rrc = rrc_;
mac = mac_;
phy = phy_;
@ -41,6 +42,12 @@ int32_t proc_sr_nr::init(mac_interface_sr_nr* mac_, phy_interface_mac_nr* phy_,
}
void proc_sr_nr::reset()
{
std::lock_guard<std::mutex> lock(mutex);
reset_unsafe();
}
void proc_sr_nr::reset_unsafe()
{
is_pending_sr = false;
}
@ -79,6 +86,7 @@ int32_t proc_sr_nr::set_config(const srsran::sr_cfg_nr_t& cfg_)
void proc_sr_nr::step(uint32_t tti)
{
std::lock_guard<std::mutex> lock(mutex);
if (!initiated) {
return;
}
@ -93,7 +101,7 @@ void proc_sr_nr::step(uint32_t tti)
// 2> initiate a Random Access procedure (see clause 5.1) on the SpCell and cancel the pending SR.
logger.info("SR: PUCCH not configured. Starting RA procedure");
mac->start_ra();
reset();
reset_unsafe();
return;
}
@ -111,12 +119,13 @@ void proc_sr_nr::step(uint32_t tti)
// ... TODO
mac->start_ra();
reset();
reset_unsafe();
}
}
bool proc_sr_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx)
{
std::lock_guard<std::mutex> lock(mutex);
// 2> when the MAC entity has an SR transmission occasion on the valid PUCCH resource for SR configured; and
if (!initiated || !cfg.enabled || !is_pending_sr) {
return false;
@ -156,6 +165,7 @@ bool proc_sr_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, boo
void proc_sr_nr::start()
{
std::lock_guard<std::mutex> lock(mutex);
if (initiated) {
if (not is_pending_sr) {
logger.info("SR: Starting procedure");

@ -45,7 +45,10 @@ public:
preamble_received_target_power = preamble_received_target_power_;
}
int tx_request(const tx_request_t& request) override { return 0; }
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>, uint16_t rnti, srsran_rnti_type_t rnti_type) override
int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>,
uint16_t rnti,
srsran_rnti_type_t rnti_type) override
{
return 0;
}

@ -39,7 +39,10 @@ public:
preamble_received_target_power = preamble_received_target_power_;
}
int tx_request(const tx_request_t& request) override { return 0; }
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>, uint16_t rnti, srsran_rnti_type_t rnti_type) override
int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>,
uint16_t rnti,
srsran_rnti_type_t rnti_type) override
{
return 0;
}

@ -40,7 +40,10 @@ public:
preamble_received_target_power = preamble_received_target_power_;
}
int tx_request(const tx_request_t& request) override { return 0; }
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>, uint16_t rnti, srsran_rnti_type_t rnti_type) override
int set_ul_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>,
uint16_t rnti,
srsran_rnti_type_t rnti_type) override
{
return 0;
}

@ -2765,6 +2765,13 @@ void rrc::release_drb(uint32_t drb_id)
{
if (drbs.find(drb_id) != drbs.end()) {
logger.info("Releasing DRB Id %d", drb_id);
// remvove RLC and PDCP for this LCID
uint32_t lcid = get_lcid_for_drb_id(drb_id);
rlc->del_bearer(lcid);
pdcp->del_bearer(lcid);
// TODO: implement bearer removal at MAC
// remove EPS bearer associated with this DRB from Stack (GW will trigger service request if needed)
stack->remove_eps_bearer(get_eps_bearer_id_for_drb_id(drb_id));
drbs.erase(drb_id);
@ -2773,6 +2780,26 @@ void rrc::release_drb(uint32_t drb_id)
}
}
/**
* @brief check if this DRB id exists and return it's LCID
*
* if the DRB couldn't be found, 0 is returned. This is an invalid
* LCID for DRB and the caller should handle it.
*/
uint32_t rrc::get_lcid_for_drb_id(const uint32_t& drb_id)
{
uint32_t lcid = 0;
if (drbs.find(drb_id) != drbs.end()) {
asn1::rrc::drb_to_add_mod_s drb_cnfg = drbs[drb_id];
if (drb_cnfg.lc_ch_id_present) {
lcid = drb_cnfg.lc_ch_id;
} else {
lcid = srsran::MAX_LTE_SRB_ID + drb_cnfg.drb_id;
}
}
return lcid;
}
uint32_t rrc::get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id)
{
// check if this bearer id exists and return it's LCID

@ -782,16 +782,16 @@ bool rrc_nr::apply_csi_meas_cfg(const asn1::rrc_nr::csi_meas_cfg_s& csi_meas_cfg
bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_common)
{
if (dl_cfg_common.init_dl_bwp_present) {
if (dl_cfg_common.freq_info_dl_present) {
if (make_phy_carrier_cfg(dl_cfg_common.freq_info_dl, &phy_cfg.carrier) == false) {
logger.warning("Warning while making carrier phy config");
return false;
}
} else {
logger.warning("Option freq_info_dl not present");
if (dl_cfg_common.freq_info_dl_present) {
if (make_phy_carrier_cfg(dl_cfg_common.freq_info_dl, &phy_cfg.carrier) == false) {
logger.warning("Warning while making carrier phy config");
return false;
}
} else {
logger.warning("Option freq_info_dl not present, S-UL not supported.");
return false;
}
if (dl_cfg_common.init_dl_bwp_present) {
if (dl_cfg_common.init_dl_bwp.pdsch_cfg_common_present) {
if (dl_cfg_common.init_dl_bwp.pdsch_cfg_common.type() ==
asn1::rrc_nr::setup_release_c<asn1::rrc_nr::pdsch_cfg_common_s>::types_opts::setup) {
@ -799,13 +799,12 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com
// Load CORESET Zero
if (pdcch_cfg_common.ctrl_res_set_zero_present) {
srsran::srsran_band_helper band_helper;
// Get band number
uint16_t band = band_helper.get_band_from_dl_arfcn(phy_cfg.carrier.absolute_frequency_point_a);
srsran::srsran_band_helper band_helper;
uint16_t band = band_helper.get_band_from_dl_arfcn(phy_cfg.carrier.dl_absolute_frequency_point_a);
// Get pointA and SSB absolute frequencies
double pointA_abs_freq_Hz = band_helper.nr_arfcn_to_freq(phy_cfg.carrier.absolute_frequency_point_a);
double pointA_abs_freq_Hz = band_helper.nr_arfcn_to_freq(phy_cfg.carrier.dl_absolute_frequency_point_a);
double ssb_abs_freq_Hz = band_helper.nr_arfcn_to_freq(phy_cfg.carrier.absolute_frequency_ssb);
// Calculate integer SSB to pointA frequency offset in Hz
@ -923,11 +922,14 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com
bool rrc_nr::apply_ul_common_cfg(const asn1::rrc_nr::ul_cfg_common_s& ul_cfg_common)
{
if (ul_cfg_common.freq_info_ul_present && ul_cfg_common.freq_info_ul.absolute_freq_point_a_present) {
// Update UL frequency point if provided
phy_cfg.carrier.ul_absolute_frequency_point_a = ul_cfg_common.freq_info_ul.absolute_freq_point_a;
}
if (ul_cfg_common.init_ul_bwp_present) {
if (ul_cfg_common.init_ul_bwp.rach_cfg_common_present) {
if (ul_cfg_common.init_ul_bwp.rach_cfg_common.type() == setup_release_c<rach_cfg_common_s>::types_opts::setup) {
rach_nr_cfg_t rach_nr_cfg = make_mac_rach_cfg(ul_cfg_common.init_ul_bwp.rach_cfg_common.setup());
rach_nr_cfg.skip_rar = args.skip_rar;
mac->set_config(rach_nr_cfg);
// Make the RACH configuration for PHY

@ -24,7 +24,7 @@
#include "dummy_rx_harq_proc.h"
#include "dummy_tx_harq_proc.h"
#include "srsenb/hdr/stack/mac/mac_nr.h"
#include "srsenb/hdr/stack/mac/nr/mac_nr.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr.h"
#include "srsenb/test/common/dummy_classes_nr.h"
#include "srsenb/test/common/rlc_test_dummy.h"
@ -353,7 +353,7 @@ public:
mac.reset(new srsenb::mac_nr{&task_sched, sched_cfg});
mac->init(srsenb::mac_nr_args_t{}, nullptr, nullptr, &rlc_obj, &rrc_obj);
std::vector<srsenb::sched_nr_interface::cell_cfg_t> cells_cfg = srsenb::get_default_cells_cfg(1, phy_cfg);
mac->cell_cfg(srsenb::sched_interface::cell_cfg_t{}, cells_cfg);
mac->cell_cfg(cells_cfg);
// add UE to scheduler
if (not use_dummy_sched and not args.wait_preamble) {

Loading…
Cancel
Save