Merge branch 'next' into agpl_next

master
Codebot 3 years ago committed by Your Name
commit a2cc847747

@ -221,8 +221,8 @@ public:
virtual int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) = 0;
/* Manages UE configuration context */
virtual int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) = 0;
virtual int ue_rem(uint16_t rnti) = 0;
virtual int ue_cfg(uint16_t rnti, const sched_interface::ue_cfg_t* cfg) = 0;
virtual int ue_rem(uint16_t rnti) = 0;
/**
* Called after Msg3 reception to set the UE C-RNTI, resolve contention, and alter the UE's configuration in the
@ -232,7 +232,7 @@ public:
* @param crnti chosen C-RNTI for the UE
* @param cfg new UE scheduler configuration
*/
virtual int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) = 0;
virtual int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface::ue_cfg_t& cfg) = 0;
/* Manages UE bearers and associated configuration */
virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg) = 0;

@ -68,7 +68,6 @@ struct cell_cfg_t {
double ul_freq_hz;
int target_pucch_sinr_db;
int target_pusch_sinr_db;
uint32_t initial_dl_cqi;
bool enable_phr_handling;
int min_phr_thres;
asn1::rrc::mob_ctrl_info_s::t304_e_ t304;

@ -51,17 +51,14 @@ public:
uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu,
uint32_t m_tmsi,
uint8_t mmec) = 0;
uint32_t m_tmsi) = 0;
virtual void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) = 0;
virtual bool user_exists(uint16_t rnti) = 0;
virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0;
virtual bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0;
virtual bool is_amf_connected() = 0;
/// TS 36.413, 8.3.1 - Initial Context Setup
virtual void ue_ctxt_setup_complete(uint16_t rnti) = 0;
virtual void ue_ctxt_setup_complete(uint16_t rnti) = 0;
};
} // namespace srsenb

@ -73,6 +73,8 @@ public:
uint32_t min_tpc_tti_interval = 1;
float ul_snr_avg_alpha = 0.05;
int init_ul_snr_value = 5;
int init_dl_cqi = 5;
float max_sib_coderate = 0.8;
};
struct cell_cfg_t {
@ -109,7 +111,6 @@ public:
uint32_t nrb_cqi;
uint32_t ncs_an;
uint32_t initial_dl_cqi;
uint32_t srs_subframe_config;
uint32_t srs_subframe_offset;
@ -313,10 +314,10 @@ public:
virtual int ul_sched(uint32_t tti, uint32_t enb_cc_idx, ul_sched_res_t& sched_result) = 0;
/* Custom */
virtual void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) = 0;
virtual std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) = 0;
virtual std::array<bool, SRSRAN_MAX_CARRIERS> get_scell_activation_mask(uint16_t rnti) = 0;
virtual int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) = 0;
virtual void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) = 0;
virtual std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) = 0;
virtual std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_activ_cc_map(uint16_t rnti) = 0;
virtual int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) = 0;
};
} // namespace srsenb

@ -35,6 +35,10 @@
#include "srsran/config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t nof_bits;
uint16_t* interleaver;
@ -87,4 +91,8 @@ SRSRAN_API uint32_t srsran_bit_diff(const uint8_t* x, const uint8_t* y, int nbit
SRSRAN_API uint32_t srsran_bit_count(uint32_t n);
#ifdef __cplusplus
}
#endif
#endif // SRSRAN_BIT_H

@ -48,6 +48,8 @@ SRSRAN_API float srsran_random_gauss_dist(srsran_random_t q, float std_dev);
SRSRAN_API bool srsran_random_bool(srsran_random_t q, float prob_true);
SRSRAN_API void srsran_random_byte_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples);
SRSRAN_API void srsran_random_bit_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples);
SRSRAN_API void srsran_random_free(srsran_random_t q);

@ -59,6 +59,13 @@ extern "C" {
// Cumulative moving average
#define SRSRAN_VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n) + 1))
// Cumulative moving average
#ifdef __cplusplus
#define SRSRAN_VEC_SAFE_CMA(data, average, n) (std::isnormal(average) ? SRSRAN_VEC_CMA(data, average, n) : (data))
#else
#define SRSRAN_VEC_SAFE_CMA(data, average, n) (isnormal(average) ? SRSRAN_VEC_CMA(data, average, n) : (data))
#endif
// Proportional moving average
#define SRSRAN_VEC_PMA(average1, n1, average2, n2) (((average1) * (n1) + (average2) * (n2)) / ((n1) + (n2)))
@ -66,7 +73,12 @@ extern "C" {
#define SRSRAN_VEC_EMA(data, average, alpha) ((alpha) * (data) + (1 - alpha) * (average))
// Safe exponential moving average
#ifdef __cplusplus
#define SRSRAN_VEC_SAFE_EMA(data, average, alpha) \
(std::isnormal(average) ? SRSRAN_VEC_EMA(data, average, alpha) : (data))
#else
#define SRSRAN_VEC_SAFE_EMA(data, average, alpha) (isnormal(average) ? SRSRAN_VEC_EMA(data, average, alpha) : (data))
#endif
static inline float srsran_convert_amplitude_to_dB(float v)
{

@ -583,7 +583,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
bool rlc_am_is_pdu_segment(uint8_t* payload);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info>& info_queue);
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);

@ -32,6 +32,7 @@
#include <string.h>
#include <strings.h>
#define SRSRAN_PDSCH_MIN_TDEC_ITERS 2
#define SRSRAN_PDSCH_MAX_TDEC_ITERS 10
#ifdef LV_HAVE_SSE
@ -442,8 +443,9 @@ bool decode_tb_cb(srsran_sch_t* q,
crc_ptr = &q->crc_tb;
}
// CRC is OK
if (!srsran_crc_checksum_byte(crc_ptr, &data[cb_idx * rlen / 8], len_crc)) {
// CRC is OK and ran the minimum number of iterations
if (!srsran_crc_checksum_byte(crc_ptr, &data[cb_idx * rlen / 8], len_crc) &&
(cb_noi >= SRSRAN_PDSCH_MIN_TDEC_ITERS)) {
softbuffer->cb_crc[cb_idx] = true;
early_stop = true;

@ -211,6 +211,10 @@ add_executable(pdcch_test pdcch_test.c)
target_link_libraries(pdcch_test srsran_phy)
foreach (nof_prb 6 15 25 50 75 100)
# Currently, the ARM platforms srsRAN has been tested are not capable of running 100PRB. So, skip 100 PRB in ARM
if (HAVE_NEON AND (${nof_prb} EQUAL 100))
continue()
endif ()
foreach (nof_ports 1 2)
foreach (cfi 1 2 3)
foreach (snr auto 15 300)

@ -20,6 +20,7 @@
*/
#include "srsran/phy/utils/random.h"
#include "srsran/phy/utils/bit.h"
#include <complex>
#include <random>
@ -45,6 +46,37 @@ public:
return dist(*mt19937);
}
void byte_vector(uint8_t* buffer, uint32_t n)
{
if (buffer == NULL || n == 0) {
return;
}
uint32_t i = 0;
uint32_t* buffer_u32 = (uint32_t*)buffer;
for (; i < n / sizeof(uint32_t); i++) {
buffer_u32[i] = (uint32_t)(*mt19937)();
}
i *= (uint32_t)sizeof(uint32_t);
for (; i < n; i++) {
buffer[i] = (uint8_t)((*mt19937)() & 0xffUL);
}
}
void bit_vector(uint8_t* buffer, uint32_t n)
{
if (buffer == NULL || n == 0) {
return;
}
uint32_t i = 0;
uint8_t* ptr = buffer;
for (; i < n / 32; i++) {
srsran_bit_unpack((uint32_t)(*mt19937)(), &ptr, 32);
}
srsran_bit_unpack((uint32_t)(*mt19937)(), &ptr, n - i * 32);
}
float gauss_dist(float sigma)
{
std::normal_distribution<float> dist(sigma);
@ -122,11 +154,22 @@ bool srsran_random_bool(srsran_random_t q, float prob_true)
return srsran_random_uniform_real_dist(q, 0, 1) < prob_true;
}
void srsran_random_byte_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples)
{
if (q == nullptr) {
return;
}
auto* h = (random_wrap*)q;
h->byte_vector(c, nsamples);
}
void srsran_random_bit_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples)
{
for (uint32_t i = 0; i < nsamples; i++) {
c[i] = (uint8_t)srsran_random_uniform_int_dist(q, 0, 1);
if (q == nullptr) {
return;
}
auto* h = (random_wrap*)q;
h->bit_vector(c, nsamples);
}
void srsran_random_free(srsran_random_t q)

@ -1179,13 +1179,24 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
std::unique_lock<std::mutex> lock(mutex);
logger.info(payload, nof_bytes, "%s Rx control PDU", RB_NAME);
logger.debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME);
rlc_status_pdu_t status;
rlc_am_read_status_pdu(payload, nof_bytes, &status);
log_rlc_am_status_pdu_to_string(logger.info, "%s Rx Status PDU: %s", &status, RB_NAME);
// make sure ACK_SN is within our Tx window
if (((MOD + status.ack_sn - vt_a) % MOD > RLC_AM_WINDOW_SIZE) ||
((MOD + vt_s - status.ack_sn) % MOD > RLC_AM_WINDOW_SIZE)) {
logger.warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.",
RB_NAME,
status.ack_sn,
vt_a,
vt_s);
return;
}
// Sec 5.2.2.2, stop poll reTx timer if status PDU comprises a positive _or_ negative acknowledgement
// for the RLC data PDU with sequence number poll_sn
if (poll_retx_timer.is_valid() && (TX_MOD_BASE(poll_sn) < TX_MOD_BASE(status.ack_sn))) {
@ -1838,6 +1849,7 @@ void rlc_am_lte::rlc_am_lte_rx::reset_status()
bool rlc_am_lte::rlc_am_lte_rx::get_do_status()
{
std::lock_guard<std::mutex> lock(mutex);
return do_status;
}
@ -1933,9 +1945,9 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui
logger.debug("Removing last NACK SN=%d", status->nacks[status->N_nack].nack_sn);
status->N_nack--;
// make sure we don't have the current ACK_SN in the NACK list
if (rlc_am_is_valid_status_pdu(*status) == false) {
if (rlc_am_is_valid_status_pdu(*status, vr_r) == false) {
// No space to send any NACKs, play safe and just ack lower edge
logger.debug("Resetting ACK_SN and N_nack to initial state");
logger.warning("Resetting ACK_SN and N_nack to initial state");
status->ack_sn = vr_r;
status->N_nack = 0;
}
@ -2405,8 +2417,13 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload)
return tmp.N_bits / 8;
}
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status)
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min)
{
// check if ACK_SN is inside Rx window
if ((MOD + status.ack_sn - rx_win_min) % MOD > RLC_AM_WINDOW_SIZE) {
return false;
}
for (uint32_t i = 0; i < status.N_nack; ++i) {
// NACK can't be larger than ACK
if ((MOD + status.ack_sn - status.nacks[i].nack_sn) % MOD > RLC_AM_WINDOW_SIZE) {

@ -1029,6 +1029,118 @@ int mac_sch_pdu_unpack_test3()
return SRSRAN_SUCCESS;
}
// Unpacking of UL-SCH PDU containing Padding, PHR and two SDUs for same LCID
int mac_sch_pdu_unpack_test4()
{
static uint8_t tv[] = {
0x3f, 0x3a, 0x23, 0x09, 0x03, 0x1e, 0xd9, 0xd0, 0x84, 0x1d, 0xc4, 0x77, 0xc7, 0x3b, 0xf0, 0x9a, 0x31, 0xc6, 0xb7,
0x48, 0x61, 0x6e, 0xc3, 0x97, 0x48, 0xa6, 0xe3, 0xac, 0xc0, 0x75, 0x9f, 0xb2, 0xc8, 0xed, 0xb0, 0xad, 0xcc, 0xc2,
0x0d, 0x28, 0xdd, 0xbb, 0x4b, 0x4c, 0xc5, 0xfc, 0x52, 0x40, 0xc2, 0x09, 0x89, 0x23, 0x77, 0x4c, 0xba, 0xbf, 0xf2,
0x9d, 0x6b, 0xb2, 0x12, 0x0b, 0x64, 0xda, 0xf8, 0x14, 0x88, 0xc4, 0xd7, 0x95, 0xec, 0xb4, 0x50, 0x37, 0x00, 0x15,
0x33, 0x52, 0x56, 0xf5, 0x5b, 0xdf, 0x18, 0xd2, 0x2b, 0xd2, 0x92, 0x1d, 0x6f, 0xfd, 0xcf, 0x82, 0x08, 0x33, 0x5c,
0x00, 0x48, 0xe4, 0xc4, 0x1f, 0x79, 0xb0, 0xd3, 0xca, 0xe8, 0xd3, 0xdf, 0x1b, 0x25, 0x35, 0x11, 0x80, 0x14, 0x29,
0x52, 0x3f, 0xfc, 0xe4, 0x5c, 0x6b, 0xe2, 0x2b, 0xed, 0xea, 0x5f, 0x4a, 0xeb, 0xa7, 0x2e, 0xaf, 0xc6, 0xa8, 0x60,
0x99, 0x72, 0x48, 0x6c, 0x51, 0x63, 0x91, 0x87, 0x74, 0x11, 0x9b, 0x9e, 0x63, 0xdb, 0x9a, 0x48, 0x37, 0x05, 0x2a,
0x63, 0xf3, 0x14, 0xc2, 0x3d, 0xff, 0x69, 0x6b, 0xaf, 0x2f, 0x13, 0x0f, 0xc8, 0x85, 0x57, 0x34, 0xd7, 0xba, 0xc5,
0x5e, 0x2f, 0xd6, 0xf9, 0xcd, 0x39, 0xd4, 0x67, 0x81, 0x0c, 0x6c, 0xab, 0x6f, 0x5f, 0xc0, 0x31, 0x9c, 0xbf, 0x9a,
0x08, 0x6e, 0xc9, 0x1b, 0x7d, 0x91, 0xa1, 0xd4, 0xc5, 0x78, 0x8f, 0x8a, 0xd6, 0xbe, 0x60, 0xcf, 0x8b, 0x99, 0xa4,
0xf2, 0x1b, 0xb0, 0x5e, 0xc6, 0x1f, 0xbe, 0x86, 0x50, 0x5a, 0x46, 0xea, 0x62, 0xb4, 0xb3, 0x7e, 0x32, 0x44, 0x1f,
0x06, 0x09, 0x97, 0x95, 0x93, 0x6d, 0x53, 0xf3, 0x3c, 0xde, 0x8c, 0xe0, 0xd0, 0xa7, 0x90, 0x2f, 0x6e, 0xaf, 0xed,
0xf4, 0xff, 0x47, 0x3a, 0xe9, 0xaa, 0xef, 0x9c, 0x28, 0x21, 0xe0, 0x47, 0x27, 0xe9, 0xde, 0xbd, 0x7c, 0x4b, 0x10,
0x6f, 0x87, 0xef, 0xfc, 0x68, 0xbf, 0xa3, 0xf8, 0xee, 0x11, 0xa8, 0xdb, 0x06, 0xa7, 0x23, 0x40, 0x91, 0xcd, 0x2f,
0x2d, 0xf5, 0x50, 0x0e, 0x3c, 0x78, 0xf7, 0x1a, 0x35, 0x74, 0x65, 0x45, 0xe3, 0xec, 0x34, 0xdf, 0x54, 0xf4, 0x83,
0x4d, 0xe2, 0x94, 0xf5, 0xbe, 0x9a, 0x9c, 0xe1, 0xdb, 0x2d, 0xae, 0x0a, 0x5b, 0xa3, 0x5b, 0x69, 0xdf, 0xd3, 0x60,
0xf9, 0x08, 0xd4, 0x5e, 0x4d, 0xb8, 0x4a, 0x82, 0x97, 0x9f, 0x76, 0x1a, 0xec, 0x58, 0xaf, 0xe1, 0x16, 0x49, 0x7d,
0xf7, 0x24, 0xab, 0xa5, 0x2f, 0x06, 0x48, 0x8a, 0x6f, 0x27, 0x5d, 0xcf, 0x20, 0x65, 0xa4, 0x7e, 0xb2, 0x5c, 0xc9,
0x34, 0xf3, 0x68, 0xaa, 0x0e, 0x54, 0x03, 0xbd, 0x35, 0x19, 0x06, 0xb2, 0x11, 0x2b, 0x5d, 0xb6, 0x5a, 0x63, 0xff,
0xe4, 0xd2, 0x26, 0x41, 0xa2, 0x47, 0xa6, 0x46, 0xc5, 0x58, 0xa2, 0x8e, 0x8d, 0x95, 0xf6, 0x37, 0xa3, 0x4a, 0x3a,
0x60, 0x7f, 0x54, 0x67, 0x32, 0x65, 0x92, 0x8f, 0x1b, 0xec, 0xf3, 0x1a, 0xd0, 0xc5, 0x41, 0x11, 0x67, 0x88, 0xb7,
0xad, 0x4d, 0x0f, 0x4f, 0xdc, 0x9c, 0xe5, 0xd2, 0xd4, 0x88, 0x1d, 0x0e, 0xe9, 0x9c, 0x62, 0x50, 0xce, 0xc7, 0xe2,
0x5e, 0xe3, 0xce, 0x51, 0xfd, 0x9e, 0x16, 0x3e, 0xaf, 0x7e, 0xc6, 0x66, 0x2b, 0x14, 0x75, 0x7b, 0xf0, 0x12, 0x60,
0xc2, 0xe6, 0xe8, 0xdf, 0xf4, 0xd1, 0x7c, 0x57, 0x21, 0x4a, 0x1e, 0x03, 0xa8, 0x01, 0xd1, 0xf9, 0xff, 0x6f, 0x10,
0x3d, 0x1e, 0x8e, 0x04, 0x84, 0xb9, 0x18, 0xfa, 0x34, 0x08, 0x0c, 0x94, 0xca, 0xf2, 0x7d, 0xaa, 0xe6, 0x4e, 0x26,
0x3d, 0x70, 0x70, 0x5c, 0x73, 0x19, 0x5d, 0x45, 0x12, 0x5c, 0xb4, 0x22, 0x9a, 0xd3, 0xb0, 0x9e, 0x57, 0x6a, 0xb6,
0x51, 0x9e, 0xbe, 0x5d, 0x33, 0x88, 0x4f, 0xb0, 0x32, 0x36, 0xfe, 0x58, 0x73, 0x6e, 0xc9, 0xcf, 0xe2, 0xe2, 0x2d,
0x27, 0xf4, 0x89, 0xdb, 0x17, 0x23, 0xae, 0xc7, 0xc1, 0x06, 0x31, 0x77, 0x57, 0xd0, 0x35, 0xb5, 0x03, 0xbe, 0x04,
0xb3, 0xf0, 0x3a, 0xb1, 0x49, 0xae, 0x20, 0x12, 0x7d, 0x02, 0xf4, 0xaa, 0x29, 0xe8, 0x34, 0x04, 0xff, 0x57, 0xb3,
0xc7, 0x19, 0xb9, 0xf8, 0x90, 0x10, 0xc8, 0xc6, 0xc5, 0xcb, 0x84, 0xca, 0x7e, 0x74, 0x04, 0x30, 0xbd, 0xb2, 0x50,
0xcf, 0x30, 0x52, 0xc3, 0xda, 0x7b, 0xac, 0x0e, 0x7f, 0xab, 0x66, 0x32, 0x72, 0x7f, 0xeb, 0x6b, 0x0f, 0xfc, 0x33,
0xd5, 0xc1, 0xff, 0x59, 0x8b, 0x7d, 0xce, 0x90, 0xad, 0x8b, 0x42, 0xfd, 0x5b, 0x72, 0x4f, 0x1e, 0x4d, 0xca, 0xca,
0x5b, 0x4a, 0x76, 0xc1, 0x7c, 0xe8, 0x40, 0x68, 0x53, 0x50, 0x64, 0x87, 0x25, 0x25, 0x86, 0x7f, 0xb1, 0x03, 0x4d,
0x41, 0xb1, 0xd8, 0x83, 0xae, 0x33, 0xf6, 0xfe, 0x52, 0x43, 0xc8, 0x1c, 0x9e, 0x12, 0x92, 0x60, 0x8f, 0x7b, 0xa0,
0xf7, 0xce, 0xf0, 0x5b, 0x55, 0x16, 0x80, 0xdb, 0x95, 0x31, 0xdf, 0xe2, 0x72, 0x90, 0xba, 0xf6, 0x3e, 0xee, 0xec,
0x3c, 0x40, 0x2f, 0x05, 0x5c, 0xcd, 0x17, 0xef, 0x2d, 0xa6, 0x6a, 0xce, 0x9d, 0x38, 0xbe, 0xf8, 0x8e, 0xd4, 0x79,
0x69, 0x69, 0xaa, 0x48, 0x4b, 0x1d, 0xd8, 0x06, 0x13, 0x17, 0xf4, 0xff, 0x53, 0x34, 0x2e, 0x58, 0x90, 0xfb, 0x70,
0x7f, 0x29, 0x16, 0xe9, 0xf7, 0xb4, 0x22, 0xb5, 0xac, 0xb0, 0x8a, 0x25, 0x19, 0xf3, 0xd0, 0x62, 0x3f, 0xed, 0x3a,
0x45, 0x00, 0x51, 0x39, 0xff, 0xa5, 0x6d, 0x2d, 0xfd, 0xfd, 0x28, 0x6d, 0x7d, 0x51, 0x84, 0x66, 0x48, 0x38, 0x88,
0xfe, 0xe4, 0x38, 0x88, 0x0a, 0x52, 0x7b, 0xda, 0xb4, 0xba, 0xc7, 0xee, 0xff, 0xc7, 0x40, 0x38, 0xc6, 0xe5, 0xa5,
0xf3, 0xe2, 0xa3, 0x1b, 0x50, 0x20, 0x6d, 0xd4, 0x86, 0xb5, 0x0c, 0x0f, 0xb3, 0xf0, 0x47, 0x3b, 0xfa, 0x99, 0xb7,
0xd4, 0x4d, 0x71, 0x9b, 0x3c, 0x71, 0x62, 0x7c, 0xa9, 0x28, 0x61, 0x4f, 0x1b, 0x43, 0xf2, 0x37, 0x93, 0x12, 0xa4,
0x67, 0x98, 0x59, 0x73, 0xa7, 0x0d, 0x64, 0xef, 0x48, 0x5e, 0x88, 0xff, 0x33, 0xd6, 0x71, 0xce, 0x12, 0xe2, 0x31,
0x8e, 0x8b, 0x59, 0xef, 0xda, 0x75, 0x32, 0xcc, 0xac, 0xc6, 0xde, 0x50, 0x2d, 0x77, 0xa9, 0xa1, 0x1e, 0xb6, 0x05,
0x0d, 0xff, 0x63, 0x96, 0xfe, 0x96, 0x6c, 0x6f, 0x65, 0x7e, 0x51, 0x96, 0x0c, 0xdd, 0xef, 0xfb, 0xb7, 0x64, 0x2d,
0x84, 0x10, 0xf3, 0x62, 0x60, 0x21, 0xd9, 0x0a, 0xc2, 0xf8, 0xc0, 0xc7, 0x05, 0xbf, 0x2a, 0x9b, 0xbe, 0xc1, 0x07,
0x2d, 0x26, 0x85, 0x7f, 0xbc, 0x91, 0x5c, 0xab, 0x8c, 0x13, 0x10, 0xba, 0x97, 0x20, 0xad, 0xfa, 0x81, 0xce, 0xd3,
0x8b, 0x90, 0xcb, 0x4b, 0x57, 0xd1, 0x0b, 0x82, 0x6c, 0xc9, 0x43, 0x74, 0xf6, 0x69, 0xf9, 0x75, 0x25, 0x8b, 0xd1,
0xd0, 0x17, 0xe5, 0xe0, 0xd1, 0x7c, 0x01, 0x7f, 0x76, 0x82, 0x4d, 0x4a, 0x0d, 0xde, 0x15, 0x58, 0x35, 0xe6, 0x63,
0xb7, 0x53, 0x2c, 0xfa, 0xc7, 0x23, 0x63, 0xc0, 0x98, 0x88, 0x4b, 0x6a, 0x59, 0x63, 0x4f, 0x39, 0x34, 0xcb, 0x3a,
0xb3, 0x42, 0xbc, 0x01, 0x8c, 0xc9, 0xdf, 0xa1, 0x22, 0x14, 0x88, 0x85, 0xcc, 0xdb, 0xb2, 0xc6, 0xa2, 0xd5, 0x2a,
0x62, 0x6d, 0xb2, 0xae, 0xd7, 0x0b, 0x11, 0x26, 0x45, 0x45, 0xf2, 0x7f, 0xf9, 0x34, 0x3c, 0xfa, 0xc0, 0x05, 0xd9,
0x61, 0x27, 0xed, 0xe9, 0xad, 0xb9, 0xc4, 0x5f, 0x80, 0x66, 0x34, 0xaa, 0xc9, 0xa1, 0x5c, 0x77, 0x79, 0x68, 0x88,
0x9f, 0xad, 0xcd, 0x91, 0x2c, 0xc6, 0xc5, 0x68, 0xc0, 0x85, 0x6e, 0x99, 0xe7, 0x95, 0x87, 0xd0, 0x42, 0x40, 0x95,
0xa1, 0xc0, 0xfb, 0xd5, 0x6a, 0xc4, 0x77, 0xc7, 0x3b, 0xf0, 0x2f, 0xc3, 0x8f, 0xdc, 0x91, 0x21, 0x08, 0x57};
uint8_t* sdu1 = &tv[6];
uint32_t sdu1_len = 9;
uint8_t* sdu2 = &tv[15];
uint32_t sdu2_len = 1048;
srsran::sch_pdu pdu(5, srslog::fetch_basic_logger("MAC"));
pdu.init_rx(sizeof(tv), true);
pdu.parse_packet(tv);
TESTASSERT(pdu.nof_subh() == 4);
// Padding
TESTASSERT(pdu.next());
TESTASSERT(pdu.get()->is_sdu() == false);
TESTASSERT(pdu.get()->ul_sch_ce_type() == srsran::ul_sch_lcid::PADDING);
// PHR
TESTASSERT(pdu.next());
TESTASSERT(pdu.get()->is_sdu() == false);
TESTASSERT(pdu.get()->ul_sch_ce_type() == srsran::ul_sch_lcid::PHR_REPORT);
TESTASSERT(pdu.get()->get_phr() == 7);
// SDU1
TESTASSERT(pdu.next());
TESTASSERT(pdu.get()->is_sdu() == true);
TESTASSERT(pdu.get()->get_sdu_lcid() == 3);
TESTASSERT(pdu.get()->get_payload_size() == sdu1_len);
TESTASSERT(memcmp(sdu1, pdu.get()->get_sdu_ptr(), sdu1_len) == 0);
// SDU2
TESTASSERT(pdu.next());
TESTASSERT(pdu.get()->is_sdu() == true);
TESTASSERT(pdu.get()->get_sdu_lcid() == 3);
TESTASSERT(pdu.get()->get_payload_size() == sdu2_len);
TESTASSERT(memcmp(sdu2, pdu.get()->get_sdu_ptr(), sdu2_len) == 0);
// end of PDU
TESTASSERT(pdu.next() == false);
fmt::memory_buffer buffer;
pdu.to_string(buffer);
std::cout << fmt::to_string(buffer) << std::endl;
#if HAVE_PCAP
pcap_handle->write_ul_crnti(tv, sizeof(tv), 0x1001, true, 1, 0);
#endif
return SRSRAN_SUCCESS;
}
int mac_slsch_pdu_unpack_test1()
{
// SL-SCH PDU captures from UXM 5G CV2X
@ -1085,6 +1197,7 @@ int main(int argc, char** argv)
TESTASSERT(mac_sch_pdu_unpack_test1() == SRSRAN_SUCCESS);
TESTASSERT(mac_sch_pdu_unpack_test2() == SRSRAN_SUCCESS);
TESTASSERT(mac_sch_pdu_unpack_test3() == SRSRAN_SUCCESS);
TESTASSERT(mac_sch_pdu_unpack_test4() == SRSRAN_SUCCESS);
TESTASSERT(mac_slsch_pdu_unpack_test1() == SRSRAN_SUCCESS);

@ -533,9 +533,7 @@ int main(int argc, char** argv)
for (uint32_t sf_idx = 0; sf_idx < nof_subframes; sf_idx++) {
/* Generate random data */
for (int j = 0; j < SRSRAN_MAX_TB; j++) {
for (int i = 0; i < MAX_DATABUFFER_SIZE; i++) {
data_tx[j][i] = (uint8_t)srsran_random_uniform_int_dist(random, 0, 255);
}
srsran_random_byte_vector(random, data_tx[j], MAX_DATABUFFER_SIZE);
}
/*

@ -88,6 +88,45 @@ int malformed_status_pdu_test()
return SRSRAN_SUCCESS;
}
// Malformed PDU captured in field-test
// 22:48:03.509077 [RLC ] [I] DRB1 Tx status PDU - ACK_SN = 205, N_nack = 98, NACK_SN =
// [752][986][109][110][111][112][113][114][115][116][117][118][119][120][121][122][123][124][125][126][127][128][129]
int malformed_status_pdu_test2()
{
uint32_t vr_a = 293;
// Construct a status PDU that ACKs SN 205, which is outside the rx window
srsran::rlc_status_pdu_t status_pdu = {};
status_pdu.ack_sn = 205;
status_pdu.N_nack = 2;
status_pdu.nacks[0].nack_sn = 752;
status_pdu.nacks[1].nack_sn = 986;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu, vr_a) == false);
// 1 SN after upper edge of Rx window will fail
status_pdu.ack_sn = 806;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu, vr_a) == false);
// The exact upper edge of Rx window should work
status_pdu.ack_sn = 805;
status_pdu.N_nack = 0;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu, vr_a) == true);
// ACK_SN is again outside of rx_window
vr_a = 0;
status_pdu.ack_sn = 742;
status_pdu.N_nack = 0;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu, vr_a) == false);
// ACK_SN is well within rx window
vr_a = 300;
status_pdu.ack_sn = 742;
status_pdu.N_nack = 0;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu, vr_a) == true);
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv)
{
srslog::init();
@ -95,6 +134,7 @@ int main(int argc, char** argv)
TESTASSERT(simple_status_pdu_test1() == SRSRAN_SUCCESS);
TESTASSERT(status_pdu_with_nacks_test1() == SRSRAN_SUCCESS);
TESTASSERT(malformed_status_pdu_test() == SRSRAN_SUCCESS);
TESTASSERT(malformed_status_pdu_test2() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;
}

@ -150,6 +150,87 @@ int test4()
return SRSRAN_SUCCESS;
}
int test5()
{
uint8_t tv[] = {
0x9a, 0x31, 0xc6, 0xb7, 0x48, 0x61, 0x6e, 0xc3, 0x97, 0x48, 0xa6, 0xe3, 0xac, 0xc0, 0x75, 0x9f, 0xb2, 0xc8, 0xed,
0xb0, 0xad, 0xcc, 0xc2, 0x0d, 0x28, 0xdd, 0xbb, 0x4b, 0x4c, 0xc5, 0xfc, 0x52, 0x40, 0xc2, 0x09, 0x89, 0x23, 0x77,
0x4c, 0xba, 0xbf, 0xf2, 0x9d, 0x6b, 0xb2, 0x12, 0x0b, 0x64, 0xda, 0xf8, 0x14, 0x88, 0xc4, 0xd7, 0x95, 0xec, 0xb4,
0x50, 0x37, 0x00, 0x15, 0x33, 0x52, 0x56, 0xf5, 0x5b, 0xdf, 0x18, 0xd2, 0x2b, 0xd2, 0x92, 0x1d, 0x6f, 0xfd, 0xcf,
0x82, 0x08, 0x33, 0x5c, 0x00, 0x48, 0xe4, 0xc4, 0x1f, 0x79, 0xb0, 0xd3, 0xca, 0xe8, 0xd3, 0xdf, 0x1b, 0x25, 0x35,
0x11, 0x80, 0x14, 0x29, 0x52, 0x3f, 0xfc, 0xe4, 0x5c, 0x6b, 0xe2, 0x2b, 0xed, 0xea, 0x5f, 0x4a, 0xeb, 0xa7, 0x2e,
0xaf, 0xc6, 0xa8, 0x60, 0x99, 0x72, 0x48, 0x6c, 0x51, 0x63, 0x91, 0x87, 0x74, 0x11, 0x9b, 0x9e, 0x63, 0xdb, 0x9a,
0x48, 0x37, 0x05, 0x2a, 0x63, 0xf3, 0x14, 0xc2, 0x3d, 0xff, 0x69, 0x6b, 0xaf, 0x2f, 0x13, 0x0f, 0xc8, 0x85, 0x57,
0x34, 0xd7, 0xba, 0xc5, 0x5e, 0x2f, 0xd6, 0xf9, 0xcd, 0x39, 0xd4, 0x67, 0x81, 0x0c, 0x6c, 0xab, 0x6f, 0x5f, 0xc0,
0x31, 0x9c, 0xbf, 0x9a, 0x08, 0x6e, 0xc9, 0x1b, 0x7d, 0x91, 0xa1, 0xd4, 0xc5, 0x78, 0x8f, 0x8a, 0xd6, 0xbe, 0x60,
0xcf, 0x8b, 0x99, 0xa4, 0xf2, 0x1b, 0xb0, 0x5e, 0xc6, 0x1f, 0xbe, 0x86, 0x50, 0x5a, 0x46, 0xea, 0x62, 0xb4, 0xb3,
0x7e, 0x32, 0x44, 0x1f, 0x06, 0x09, 0x97, 0x95, 0x93, 0x6d, 0x53, 0xf3, 0x3c, 0xde, 0x8c, 0xe0, 0xd0, 0xa7, 0x90,
0x2f, 0x6e, 0xaf, 0xed, 0xf4, 0xff, 0x47, 0x3a, 0xe9, 0xaa, 0xef, 0x9c, 0x28, 0x21, 0xe0, 0x47, 0x27, 0xe9, 0xde,
0xbd, 0x7c, 0x4b, 0x10, 0x6f, 0x87, 0xef, 0xfc, 0x68, 0xbf, 0xa3, 0xf8, 0xee, 0x11, 0xa8, 0xdb, 0x06, 0xa7, 0x23,
0x40, 0x91, 0xcd, 0x2f, 0x2d, 0xf5, 0x50, 0x0e, 0x3c, 0x78, 0xf7, 0x1a, 0x35, 0x74, 0x65, 0x45, 0xe3, 0xec, 0x34,
0xdf, 0x54, 0xf4, 0x83, 0x4d, 0xe2, 0x94, 0xf5, 0xbe, 0x9a, 0x9c, 0xe1, 0xdb, 0x2d, 0xae, 0x0a, 0x5b, 0xa3, 0x5b,
0x69, 0xdf, 0xd3, 0x60, 0xf9, 0x08, 0xd4, 0x5e, 0x4d, 0xb8, 0x4a, 0x82, 0x97, 0x9f, 0x76, 0x1a, 0xec, 0x58, 0xaf,
0xe1, 0x16, 0x49, 0x7d, 0xf7, 0x24, 0xab, 0xa5, 0x2f, 0x06, 0x48, 0x8a, 0x6f, 0x27, 0x5d, 0xcf, 0x20, 0x65, 0xa4,
0x7e, 0xb2, 0x5c, 0xc9, 0x34, 0xf3, 0x68, 0xaa, 0x0e, 0x54, 0x03, 0xbd, 0x35, 0x19, 0x06, 0xb2, 0x11, 0x2b, 0x5d,
0xb6, 0x5a, 0x63, 0xff, 0xe4, 0xd2, 0x26, 0x41, 0xa2, 0x47, 0xa6, 0x46, 0xc5, 0x58, 0xa2, 0x8e, 0x8d, 0x95, 0xf6,
0x37, 0xa3, 0x4a, 0x3a, 0x60, 0x7f, 0x54, 0x67, 0x32, 0x65, 0x92, 0x8f, 0x1b, 0xec, 0xf3, 0x1a, 0xd0, 0xc5, 0x41,
0x11, 0x67, 0x88, 0xb7, 0xad, 0x4d, 0x0f, 0x4f, 0xdc, 0x9c, 0xe5, 0xd2, 0xd4, 0x88, 0x1d, 0x0e, 0xe9, 0x9c, 0x62,
0x50, 0xce, 0xc7, 0xe2, 0x5e, 0xe3, 0xce, 0x51, 0xfd, 0x9e, 0x16, 0x3e, 0xaf, 0x7e, 0xc6, 0x66, 0x2b, 0x14, 0x75,
0x7b, 0xf0, 0x12, 0x60, 0xc2, 0xe6, 0xe8, 0xdf, 0xf4, 0xd1, 0x7c, 0x57, 0x21, 0x4a, 0x1e, 0x03, 0xa8, 0x01, 0xd1,
0xf9, 0xff, 0x6f, 0x10, 0x3d, 0x1e, 0x8e, 0x04, 0x84, 0xb9, 0x18, 0xfa, 0x34, 0x08, 0x0c, 0x94, 0xca, 0xf2, 0x7d,
0xaa, 0xe6, 0x4e, 0x26, 0x3d, 0x70, 0x70, 0x5c, 0x73, 0x19, 0x5d, 0x45, 0x12, 0x5c, 0xb4, 0x22, 0x9a, 0xd3, 0xb0,
0x9e, 0x57, 0x6a, 0xb6, 0x51, 0x9e, 0xbe, 0x5d, 0x33, 0x88, 0x4f, 0xb0, 0x32, 0x36, 0xfe, 0x58, 0x73, 0x6e, 0xc9,
0xcf, 0xe2, 0xe2, 0x2d, 0x27, 0xf4, 0x89, 0xdb, 0x17, 0x23, 0xae, 0xc7, 0xc1, 0x06, 0x31, 0x77, 0x57, 0xd0, 0x35,
0xb5, 0x03, 0xbe, 0x04, 0xb3, 0xf0, 0x3a, 0xb1, 0x49, 0xae, 0x20, 0x12, 0x7d, 0x02, 0xf4, 0xaa, 0x29, 0xe8, 0x34,
0x04, 0xff, 0x57, 0xb3, 0xc7, 0x19, 0xb9, 0xf8, 0x90, 0x10, 0xc8, 0xc6, 0xc5, 0xcb, 0x84, 0xca, 0x7e, 0x74, 0x04,
0x30, 0xbd, 0xb2, 0x50, 0xcf, 0x30, 0x52, 0xc3, 0xda, 0x7b, 0xac, 0x0e, 0x7f, 0xab, 0x66, 0x32, 0x72, 0x7f, 0xeb,
0x6b, 0x0f, 0xfc, 0x33, 0xd5, 0xc1, 0xff, 0x59, 0x8b, 0x7d, 0xce, 0x90, 0xad, 0x8b, 0x42, 0xfd, 0x5b, 0x72, 0x4f,
0x1e, 0x4d, 0xca, 0xca, 0x5b, 0x4a, 0x76, 0xc1, 0x7c, 0xe8, 0x40, 0x68, 0x53, 0x50, 0x64, 0x87, 0x25, 0x25, 0x86,
0x7f, 0xb1, 0x03, 0x4d, 0x41, 0xb1, 0xd8, 0x83, 0xae, 0x33, 0xf6, 0xfe, 0x52, 0x43, 0xc8, 0x1c, 0x9e, 0x12, 0x92,
0x60, 0x8f, 0x7b, 0xa0, 0xf7, 0xce, 0xf0, 0x5b, 0x55, 0x16, 0x80, 0xdb, 0x95, 0x31, 0xdf, 0xe2, 0x72, 0x90, 0xba,
0xf6, 0x3e, 0xee, 0xec, 0x3c, 0x40, 0x2f, 0x05, 0x5c, 0xcd, 0x17, 0xef, 0x2d, 0xa6, 0x6a, 0xce, 0x9d, 0x38, 0xbe,
0xf8, 0x8e, 0xd4, 0x79, 0x69, 0x69, 0xaa, 0x48, 0x4b, 0x1d, 0xd8, 0x06, 0x13, 0x17, 0xf4, 0xff, 0x53, 0x34, 0x2e,
0x58, 0x90, 0xfb, 0x70, 0x7f, 0x29, 0x16, 0xe9, 0xf7, 0xb4, 0x22, 0xb5, 0xac, 0xb0, 0x8a, 0x25, 0x19, 0xf3, 0xd0,
0x62, 0x3f, 0xed, 0x3a, 0x45, 0x00, 0x51, 0x39, 0xff, 0xa5, 0x6d, 0x2d, 0xfd, 0xfd, 0x28, 0x6d, 0x7d, 0x51, 0x84,
0x66, 0x48, 0x38, 0x88, 0xfe, 0xe4, 0x38, 0x88, 0x0a, 0x52, 0x7b, 0xda, 0xb4, 0xba, 0xc7, 0xee, 0xff, 0xc7, 0x40,
0x38, 0xc6, 0xe5, 0xa5, 0xf3, 0xe2, 0xa3, 0x1b, 0x50, 0x20, 0x6d, 0xd4, 0x86, 0xb5, 0x0c, 0x0f, 0xb3, 0xf0, 0x47,
0x3b, 0xfa, 0x99, 0xb7, 0xd4, 0x4d, 0x71, 0x9b, 0x3c, 0x71, 0x62, 0x7c, 0xa9, 0x28, 0x61, 0x4f, 0x1b, 0x43, 0xf2,
0x37, 0x93, 0x12, 0xa4, 0x67, 0x98, 0x59, 0x73, 0xa7, 0x0d, 0x64, 0xef, 0x48, 0x5e, 0x88, 0xff, 0x33, 0xd6, 0x71,
0xce, 0x12, 0xe2, 0x31, 0x8e, 0x8b, 0x59, 0xef, 0xda, 0x75, 0x32, 0xcc, 0xac, 0xc6, 0xde, 0x50, 0x2d, 0x77, 0xa9,
0xa1, 0x1e, 0xb6, 0x05, 0x0d, 0xff, 0x63, 0x96, 0xfe, 0x96, 0x6c, 0x6f, 0x65, 0x7e, 0x51, 0x96, 0x0c, 0xdd, 0xef,
0xfb, 0xb7, 0x64, 0x2d, 0x84, 0x10, 0xf3, 0x62, 0x60, 0x21, 0xd9, 0x0a, 0xc2, 0xf8, 0xc0, 0xc7, 0x05, 0xbf, 0x2a,
0x9b, 0xbe, 0xc1, 0x07, 0x2d, 0x26, 0x85, 0x7f, 0xbc, 0x91, 0x5c, 0xab, 0x8c, 0x13, 0x10, 0xba, 0x97, 0x20, 0xad,
0xfa, 0x81, 0xce, 0xd3, 0x8b, 0x90, 0xcb, 0x4b, 0x57, 0xd1, 0x0b, 0x82, 0x6c, 0xc9, 0x43, 0x74, 0xf6, 0x69, 0xf9,
0x75, 0x25, 0x8b, 0xd1, 0xd0, 0x17, 0xe5, 0xe0, 0xd1, 0x7c, 0x01, 0x7f, 0x76, 0x82, 0x4d, 0x4a, 0x0d, 0xde, 0x15,
0x58, 0x35, 0xe6, 0x63, 0xb7, 0x53, 0x2c, 0xfa, 0xc7, 0x23, 0x63, 0xc0, 0x98, 0x88, 0x4b, 0x6a, 0x59, 0x63, 0x4f,
0x39, 0x34, 0xcb, 0x3a, 0xb3, 0x42, 0xbc, 0x01, 0x8c, 0xc9, 0xdf, 0xa1, 0x22, 0x14, 0x88, 0x85, 0xcc, 0xdb, 0xb2,
0xc6, 0xa2, 0xd5, 0x2a, 0x62, 0x6d, 0xb2, 0xae, 0xd7, 0x0b, 0x11, 0x26, 0x45, 0x45, 0xf2, 0x7f, 0xf9, 0x34, 0x3c,
0xfa, 0xc0, 0x05, 0xd9, 0x61, 0x27, 0xed, 0xe9, 0xad, 0xb9, 0xc4, 0x5f, 0x80, 0x66, 0x34, 0xaa, 0xc9, 0xa1, 0x5c,
0x77, 0x79, 0x68, 0x88, 0x9f, 0xad, 0xcd, 0x91, 0x2c, 0xc6, 0xc5, 0x68, 0xc0, 0x85, 0x6e, 0x99, 0xe7, 0x95, 0x87,
0xd0, 0x42, 0x40, 0x95, 0xa1, 0xc0, 0xfb, 0xd5, 0x6a, 0xc4, 0x77, 0xc7, 0x3b, 0xf0, 0x2f, 0xc3, 0x8f, 0xdc, 0x91,
0x21, 0x08, 0x57};
srsran::rlc_amd_pdu_header_t h;
srsran::byte_buffer_t b1;
memcpy(b1.msg, tv, sizeof(tv));
b1.N_bytes = sizeof(tv);
uint32_t nof_payload_bytes = sizeof(tv);
rlc_am_read_data_pdu_header(&b1.msg, &nof_payload_bytes, &h);
TESTASSERT(nof_payload_bytes == 1046);
TESTASSERT(RLC_DC_FIELD_DATA_PDU == h.dc);
TESTASSERT(RLC_FI_FIELD_NOT_START_OR_END_ALIGNED == h.fi);
TESTASSERT(0 == h.N_li);
TESTASSERT(0 == h.lsf);
TESTASSERT(0 == h.p);
TESTASSERT(0 == h.rf);
TESTASSERT(0 == h.so);
TESTASSERT(561 == h.sn);
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv)
{
srslog::init();
@ -158,6 +239,7 @@ int main(int argc, char** argv)
TESTASSERT(test2() == SRSRAN_SUCCESS);
TESTASSERT(test3() == SRSRAN_SUCCESS);
TESTASSERT(test4() == SRSRAN_SUCCESS);
TESTASSERT(test5() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;
}

@ -199,6 +199,7 @@ int basic_test()
rlc_status_pdu_t status_check = {};
rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_check);
TESTASSERT(status_check.ack_sn == 5); // 5 is the last SN that was not received.
TESTASSERT(rlc_am_is_valid_status_pdu(status_check));
// Write status PDU to RLC1
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
@ -3367,6 +3368,112 @@ bool incorrect_status_pdu_test()
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
TESTASSERT(tester.protocol_failure_triggered == true);
return SRSRAN_SUCCESS;
}
/// The test checks the correct detection of an out-of-order status PDUs
/// In contrast to the without explicitly NACK-ing specific SNs
bool incorrect_status_pdu_test2()
{
rlc_am_tester tester;
srsran::timer_handler timers(8);
int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1;
}
if (not rlc2.configure(rlc_config_t::default_rlc_am_config())) {
return -1;
}
// Push 10 SDUs into RLC1
const uint32_t n_sdus = 10;
unique_byte_buffer_t sdu_bufs[n_sdus];
for (uint32_t i = 0; i < n_sdus; i++) {
sdu_bufs[i] = srsran::make_byte_buffer();
sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte
sdu_bufs[i]->msg[0] = i; // Write the index into the buffer
rlc1.write_sdu(std::move(sdu_bufs[i]));
}
// Read 10 PDUs from RLC1 (1 byte each) and push half of them to RLC2
const uint32_t n_pdus = n_sdus;
byte_buffer_t pdu_bufs[n_pdus];
for (uint32_t i = 0; i < n_pdus; i++) {
len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 2 byte header + 1 byte payload
pdu_bufs[i].N_bytes = len;
if (i < 5) {
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes);
}
}
TESTASSERT(0 == rlc1.get_buffer_state());
// Construct a status PDU that ACKs all SNs
rlc_status_pdu_t status_pdu = {};
status_pdu.ack_sn = 5;
status_pdu.N_nack = 0;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu));
// pack PDU and write to RLC
byte_buffer_t status_buf;
rlc_am_write_status_pdu(&status_pdu, &status_buf);
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
TESTASSERT(tester.protocol_failure_triggered == false);
// construct a valid but conflicting status PDU that acks a lower SN and requests SN=1 for retx
status_pdu.ack_sn = 3;
status_pdu.N_nack = 1;
status_pdu.nacks[0].nack_sn = 1;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu));
// pack and write to RLC again
rlc_am_write_status_pdu(&status_pdu, &status_buf);
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
// the PDU should be dropped
// resend first Status PDU again
status_pdu.ack_sn = 5;
status_pdu.N_nack = 0;
TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu));
// pack and write to RLC again
rlc_am_write_status_pdu(&status_pdu, &status_buf);
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
// retransmit all outstanding PDUs
for (int i = 0; i < 5; i++) {
byte_buffer_t retx;
retx.N_bytes = rlc1.read_pdu(retx.msg, 3);
rlc2.write_pdu(retx.msg, retx.N_bytes);
// Step timers until reordering timeout expires
int cnt = 5;
while (cnt--) {
timers.step_all();
}
// read status
byte_buffer_t status_buf;
status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10);
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);
}
TESTASSERT(tester.sdus.size() == n_sdus);
for (uint32_t i = 0; i < tester.sdus.size(); i++) {
TESTASSERT(tester.sdus[i]->N_bytes == 1);
}
return SRSRAN_SUCCESS;
}
@ -3766,6 +3873,11 @@ int main(int argc, char** argv)
exit(-1);
};
if (incorrect_status_pdu_test2()) {
printf("incorrect_status_pdu_test2 failed\n");
exit(-1);
};
if (discard_test()) {
printf("discard_test failed\n");
exit(-1);

@ -176,6 +176,8 @@ enable = false
# min_tpc_tti_interval: Minimum TTI interval between TPCs different than 1
# ul_snr_avg_alpha: Exponential Average alpha coefficient used in estimation of UL SNR
# init_ul_snr_value: Initial UL SNR value used for computing MCS in the first UL grant
# init_dl_cqi: DL CQI value used before any CQI report is available to the eNB
# max_sib_coderate: Upper bound on SIB and RAR grants coderate
#
#####################################################################
[scheduler]
@ -198,6 +200,8 @@ enable = false
#min_tpc_tti_interval = 1
#ul_snr_avg_alpha=0.05
#init_ul_snr_value=5
#init_dl_cqi=5
#max_sib_coderate=0.3
#####################################################################
# eMBMS configuration options

@ -149,7 +149,7 @@ private:
phy_interface_stack_lte* phy = nullptr;
// state
bool started = false;
std::atomic<bool> started{false};
srsran::dyn_blocking_queue<stack_metrics_t> pending_stack_metrics;
};

@ -86,9 +86,9 @@ public:
int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override;
/* Manages UE scheduling context */
int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override;
int ue_cfg(uint16_t rnti, const sched_interface::ue_cfg_t* cfg) override;
int ue_rem(uint16_t rnti) override;
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override;
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface::ue_cfg_t& cfg) override;
// Indicates that the PHY config dedicated has been enabled or not
void phy_config_enabled(uint16_t rnti, bool enabled) override;
@ -114,10 +114,8 @@ public:
const uint8_t mcch_payload_length) override;
private:
static const uint32_t cfi = 3;
bool check_ue_active(uint16_t rnti);
uint16_t allocate_ue();
uint16_t allocate_ue(uint32_t enb_cc_idx);
bool is_valid_rnti_unprotected(uint16_t rnti);
srslog::basic_logger& logger;

@ -81,10 +81,10 @@ public:
/* Custom functions
*/
void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) final;
std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) final;
std::array<bool, SRSRAN_MAX_CARRIERS> get_scell_activation_mask(uint16_t rnti) final;
int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) final;
void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) final;
std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) final;
std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_activ_cc_map(uint16_t rnti) final;
int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) final;
class carrier_sched;

@ -121,6 +121,7 @@ public:
} else {
ch_snr.acc_tpc_values = 0;
ch_snr.snr_avg.push(ch_snr.pending_snr, ch_snr.last_snr_sample_count);
ch_snr.last_snr_sample = ch_snr.pending_snr;
ch_snr.last_snr_sample_count = 1;
}
ch_snr.pending_snr = null_snr;
@ -175,7 +176,7 @@ private:
float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB;
if (target_snr_dB < 0) {
// undefined target sinr case, or no more PHR
// undefined target SINR case
return encode_tpc_delta(0);
}
if ((tti_count - ch_snr.last_tpc_tti_count) < min_tpc_tti_interval) {
@ -185,12 +186,13 @@ private:
if (cc == PUSCH_CODE and last_phr < 0 and not ch_snr.phr_flag) {
// if negative PHR and PUSCH
logger.info("TPC: rnti=0x%x, PUSCH command=0 due to PHR=%d<0", rnti, last_phr);
ch_snr.phr_flag = true;
return encode_tpc_delta(-1);
ch_snr.phr_flag = true;
ch_snr.pending_delta = -1;
return encode_tpc_delta(ch_snr.pending_delta);
}
// target SINR is finite and there is power headroom
float diff = target_snr_dB - ch_snr.snr_avg.value();
float diff = target_snr_dB - ch_snr.last_snr_sample;
diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values;
if (diff >= 1) {
ch_snr.pending_delta = diff > 3 ? 3 : 1;
@ -203,6 +205,15 @@ private:
ch_snr.pending_delta = -1;
ch_snr.last_tpc_tti_count = tti_count;
}
if (ch_snr.pending_delta != 0) {
logger.debug("TPC: rnti=0x%x, %s command=%d, last SNR=%d, SNR average=%f, diff_acc=%f",
rnti,
cc == PUSCH_CODE ? "PUSCH" : "PUCCH",
encode_tpc_delta(ch_snr.pending_delta),
ch_snr.last_snr_sample,
ch_snr.snr_avg.value(),
diff);
}
return encode_tpc_delta(ch_snr.pending_delta);
}
@ -230,6 +241,7 @@ private:
// SNR average estimation with irregular sample spacing
uint32_t last_snr_sample_count = 1; // jump in spacing
srsran::exp_average_irreg_sampling<float> snr_avg;
int last_snr_sample;
// Accumulation of past TPC commands
srsran::sliding_sum<int> win_tpc_values;
int8_t pending_delta = 0;
@ -237,7 +249,9 @@ private:
uint32_t last_tpc_tti_count = 0;
explicit ul_ch_snr_estim(float exp_avg_alpha, int initial_snr) :
snr_avg(exp_avg_alpha, initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)
snr_avg(exp_avg_alpha, initial_snr),
win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS),
last_snr_sample(initial_snr)
{}
};
std::array<ul_ch_snr_estim, nof_ul_ch_code> snr_estim_list;

@ -131,7 +131,7 @@ class ue : public srsran::read_pdu_interface, public mac_ta_ue_interface
{
public:
ue(uint16_t rnti,
uint32_t nof_prb,
uint32_t enb_cc_idx,
sched_interface* sched,
rrc_interface_mac* rrc_,
rlc_interface_mac* rlc,
@ -141,9 +141,11 @@ public:
srsran::obj_pool_itf<ue_cc_softbuffers>* softbuffer_pool);
virtual ~ue();
void reset();
void start_pcap(srsran::mac_pcap* pcap_);
void start_pcap_net(srsran::mac_pcap_net* pcap_net_);
void reset();
void start_pcap(srsran::mac_pcap* pcap_);
void start_pcap_net(srsran::mac_pcap_net* pcap_net_);
void ue_cfg(const sched_interface::ue_cfg_t& ue_cfg);
void set_tti(uint32_t tti);
uint16_t get_rnti() const { return rnti; }
uint32_t set_ta(int ta) override;
@ -154,7 +156,7 @@ public:
void set_active(bool active) { active_state.store(active, std::memory_order_relaxed); }
bool is_active() const { return active_state.load(std::memory_order_relaxed); }
uint8_t* generate_pdu(uint32_t ue_cc_idx,
uint8_t* generate_pdu(uint32_t enb_cc_idx,
uint32_t harq_pid,
uint32_t tb_idx,
const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
@ -163,12 +165,12 @@ public:
uint8_t*
generate_mch_pdu(uint32_t harq_pid, sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems, uint32_t grant_size);
srsran_softbuffer_tx_t* get_tx_softbuffer(uint32_t ue_cc_idx, uint32_t harq_process, uint32_t tb_idx);
srsran_softbuffer_rx_t* get_rx_softbuffer(uint32_t ue_cc_idx, uint32_t tti);
srsran_softbuffer_tx_t* get_tx_softbuffer(uint32_t enb_cc_idx, uint32_t harq_process, uint32_t tb_idx);
srsran_softbuffer_rx_t* get_rx_softbuffer(uint32_t enb_cc_idx, uint32_t tti);
uint8_t* request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len);
uint8_t* request_buffer(uint32_t tti, uint32_t enb_cc_idx, uint32_t len);
void process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs);
srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t ue_cc_idx);
srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t enb_cc_idx);
void clear_old_buffers(uint32_t tti);
void metrics_read(mac_ue_metrics_t* metrics_);
@ -223,7 +225,7 @@ private:
std::mutex mutex;
std::mutex rx_buffers_mutex;
const uint8_t UL_CC_IDX = 0; ///< Passed to write CC index in PCAP (TODO: use actual CC idx)
static const uint8_t UL_CC_IDX = 0; ///< Passed to write CC index in PCAP
};
} // namespace srsenb

@ -23,6 +23,7 @@
#include "srsenb/hdr/common/common_enb.h"
#include "srsran/adt/circular_map.h"
#include "srsran/adt/optional.h"
#include "srsran/asn1/asn1_utils.h"
#include "srsran/asn1/ngap.h"
#include "srsran/common/bcd_helpers.h"
@ -36,8 +37,11 @@
#include "srsran/interfaces/gnb_ngap_interfaces.h"
#include "srsran/interfaces/gnb_rrc_nr_interfaces.h"
#include "srsran/srslog/srslog.h"
#include <iostream>
#include <unordered_map>
namespace srsenb {
class ngap : public ngap_interface_rrc_nr
{
public:
@ -51,21 +55,22 @@ public:
void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu){};
srsran::unique_byte_buffer_t pdu);
void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu,
uint32_t m_tmsi,
uint8_t mmec){};
uint32_t s_tmsi);
void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu){};
bool user_exists(uint16_t rnti) { return true; };
void user_mod(uint16_t old_rnti, uint16_t new_rnti){};
bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; };
bool is_amf_connected();
/// TS 36.413, 8.3.1 - Initial Context Setup
void ue_ctxt_setup_complete(uint16_t rnti){};
bool send_error_indication(const asn1::ngap_nr::cause_c& cause,
srsran::optional<uint32_t> ran_ue_ngap_id = {},
srsran::optional<uint32_t> amf_ue_ngap_id = {});
void ue_ctxt_setup_complete(uint16_t rnti);
// Stack interface
bool
@ -91,7 +96,7 @@ private:
struct sockaddr_in amf_addr = {}; // AMF address
bool amf_connected = false;
bool running = false;
uint32_t next_enb_ue_ngap_id = 1; // Next ENB-side UE identifier
uint32_t next_gnb_ue_ngap_id = 1; // Next GNB-side UE identifier
uint16_t next_ue_stream_id = 1; // Next UE SCTP stream identifier
srsran::unique_timer amf_connect_timer, ngsetup_timeout;
@ -99,8 +104,82 @@ private:
asn1::ngap_nr::tai_s tai;
asn1::ngap_nr::nr_cgi_s nr_cgi;
// Moved into NGAP class to avoid redifinition (Introduce new namespace?)
struct ue_ctxt_t {
static const uint32_t invalid_gnb_id = std::numeric_limits<uint32_t>::max();
uint16_t rnti = SRSRAN_INVALID_RNTI;
uint32_t ran_ue_ngap_id = invalid_gnb_id;
srsran::optional<uint32_t> amf_ue_ngap_id;
uint32_t gnb_cc_idx = 0;
struct timeval init_timestamp = {};
// AMF identifier
uint16_t amf_set_id;
uint8_t amf_pointer;
uint8_t amf_region_id;
};
asn1::ngap_nr::ng_setup_resp_s ngsetupresponse;
int build_tai_cgi();
bool connect_amf();
bool setup_ng();
bool sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t rnti, const char* procedure_name);
bool handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu);
bool handle_successfuloutcome(const asn1::ngap_nr::successful_outcome_s& msg);
bool handle_unsuccessfuloutcome(const asn1::ngap_nr::unsuccessful_outcome_s& msg);
bool handle_initiatingmessage(const asn1::ngap_nr::init_msg_s& msg);
bool handle_dlnastransport(const asn1::ngap_nr::dl_nas_transport_s& msg);
bool handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg);
bool handle_ngsetupfailure(const asn1::ngap_nr::ng_setup_fail_s& msg);
bool handle_initialctxtsetuprequest(const asn1::ngap_nr::init_context_setup_request_s& msg);
struct ue {
explicit ue(ngap* ngap_ptr_);
bool send_initialuemessage(asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu,
bool has_tmsi,
uint32_t s_tmsi = 0);
bool send_ulnastransport(srsran::unique_byte_buffer_t pdu);
bool was_uectxtrelease_requested() const { return release_requested; }
void ue_ctxt_setup_complete();
ue_ctxt_t ctxt = {};
uint16_t stream_id = 1;
private:
// args
ngap* ngap_ptr;
// state
bool release_requested = false;
};
class user_list
{
public:
using value_type = std::unique_ptr<ue>;
using iterator = std::unordered_map<uint32_t, value_type>::iterator;
using const_iterator = std::unordered_map<uint32_t, value_type>::const_iterator;
using pair_type = std::unordered_map<uint32_t, value_type>::value_type;
ue* find_ue_rnti(uint16_t rnti);
ue* find_ue_gnbid(uint32_t gnbid);
ue* find_ue_amfid(uint32_t amfid);
ue* add_user(value_type user);
void erase(ue* ue_ptr);
iterator begin() { return users.begin(); }
iterator end() { return users.end(); }
const_iterator cbegin() const { return users.begin(); }
const_iterator cend() const { return users.end(); }
size_t size() const { return users.size(); }
private:
std::unordered_map<uint32_t, std::unique_ptr<ue> > users; // maps ran_ue_ngap_id to user
};
user_list users;
// procedures
class ng_setup_proc_t
{
@ -123,15 +202,7 @@ private:
ngap* ngap_ptr = nullptr;
};
void build_tai_cgi();
bool connect_amf();
bool setup_ng();
bool sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t rnti, const char* procedure_name);
bool handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu);
bool handle_successfuloutcome(const asn1::ngap_nr::successful_outcome_s& msg);
bool handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg);
ue* handle_ngapmsg_ue_id(uint32_t gnb_id, uint32_t amf_id);
srsran::proc_t<ng_setup_proc_t> ngsetup_proc;

@ -79,6 +79,13 @@ int enb::init(const all_args_t& args_)
return SRSRAN_ERROR;
}
if (ret == SRSRAN_SUCCESS) {
if (lte_stack->init(args.stack, rrc_cfg, lte_phy.get()) != SRSRAN_SUCCESS) {
srsran::console("Error initializing stack.\n");
ret = SRSRAN_ERROR;
}
}
// Init Radio
if (lte_radio->init(args.rf, lte_phy.get())) {
srsran::console("Error initializing radio.\n");
@ -93,14 +100,6 @@ int enb::init(const all_args_t& args_)
}
}
// Only init Stack if both radio and PHY could be initialized
if (ret == SRSRAN_SUCCESS) {
if (lte_stack->init(args.stack, rrc_cfg, lte_phy.get()) != SRSRAN_SUCCESS) {
srsran::console("Error initializing stack.\n");
ret = SRSRAN_ERROR;
}
}
stack = std::move(lte_stack);
phy = std::move(lte_phy);
radio = std::move(lte_radio);

@ -767,7 +767,6 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
parse_default_field(cell_cfg.ul_earfcn, cellroot, "ul_earfcn", 0u); // will be derived from DL EARFCN If not set
parse_default_field(
cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx);
parse_default_field(cell_cfg.initial_dl_cqi, cellroot, "initial_dl_cqi", 5u);
parse_default_field(cell_cfg.meas_cfg.meas_gap_period, cellroot, "meas_gap_period", 0u);
if (cellroot.exists("meas_gap_offset_subframe")) {
cell_cfg.meas_cfg.meas_gap_offset_subframe.resize(cellroot["meas_gap_offset_subframe"].getLength());

@ -167,6 +167,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("scheduler.min_tpc_tti_interval", bpo::value<uint32_t>(&args->stack.mac.sched.min_tpc_tti_interval)->default_value(1), "Minimum TTI interval between positive or negative TPCs")
("scheduler.ul_snr_avg_alpha", bpo::value<float>(&args->stack.mac.sched.ul_snr_avg_alpha)->default_value(0.05), "Exponential Average alpha coefficient used in estimation of UL SNR")
("scheduler.init_ul_snr_value", bpo::value<int>(&args->stack.mac.sched.init_ul_snr_value)->default_value(5), "Initial UL SNR value used for computing MCS in the first UL grant")
("scheduler.init_dl_cqi", bpo::value<int>(&args->stack.mac.sched.init_dl_cqi)->default_value(5), "DL CQI value used before any CQI report is available to the eNB")
("scheduler.max_sib_coderate", bpo::value<float>(&args->stack.mac.sched.max_sib_coderate)->default_value(0.8), "Upper bound on SIB and RAR grants coderate")
/* Downlink Channel emulator section */
@ -450,6 +452,61 @@ void parse_args(all_args_t* args, int argc, char* argv[])
static bool do_metrics = false;
static bool do_padding = false;
static void execute_cmd(metrics_stdout* metrics, srsenb::enb_command_interface* control, const string& cmd_line)
{
vector<string> cmd;
srsran::string_parse_list(cmd_line, ' ', cmd);
if (cmd[0] == "t") {
do_metrics = !do_metrics;
if (do_metrics) {
cout << "Enter t to stop trace." << endl;
} else {
cout << "Enter t to restart trace." << endl;
}
metrics->toggle_print(do_metrics);
} else if (cmd[0] == "sleep") {
if (cmd.size() != 2) {
cout << "Usage: " << cmd[0] << " [number of seconds]" << endl;
return;
}
int nseconds = srsran::string_cast<int>(cmd[1]);
if (nseconds <= 0) {
return;
}
std::this_thread::sleep_for(std::chrono::seconds(nseconds));
} else if (cmd[0] == "p") {
do_padding = !do_padding;
if (do_padding) {
cout << "Enter p to stop padding." << endl;
} else {
cout << "Enter p to restart padding." << endl;
}
control->toggle_padding();
} else if (cmd[0] == "q") {
raise(SIGTERM);
} else if (cmd[0] == "cell_gain") {
if (cmd.size() != 3) {
cout << "Usage: " << cmd[0] << " [cell identifier] [gain in dB]" << endl;
return;
}
// Parse command arguments
uint32_t cell_id = srsran::string_cast<uint32_t>(cmd[1]);
float gain_db = srsran::string_cast<float>(cmd[2]);
// Set cell gain
control->cmd_cell_gain(cell_id, gain_db);
} else {
cout << "Available commands: " << endl;
cout << " t: starts console trace" << endl;
cout << " q: quit srsenb" << endl;
cout << " cell_gain: set relative cell gain" << endl;
cout << " sleep: pauses the commmand line operation for a given time in seconds" << endl;
cout << " p: starts MAC padding" << endl;
cout << endl;
}
}
static void* input_loop(metrics_stdout* metrics, srsenb::enb_command_interface* control)
{
struct pollfd pfd = {STDIN_FILENO, POLLIN, 0};
@ -463,45 +520,11 @@ static void* input_loop(metrics_stdout* metrics, srsenb::enb_command_interface*
cout << "Closing stdin thread." << endl;
break;
} else if (not input_line.empty()) {
vector<string> cmd;
srsran::string_parse_list(input_line, ' ', cmd);
if (cmd[0] == "t") {
do_metrics = !do_metrics;
if (do_metrics) {
cout << "Enter t to stop trace." << endl;
} else {
cout << "Enter t to restart trace." << endl;
}
metrics->toggle_print(do_metrics);
} else if (cmd[0] == "p") {
do_padding = !do_padding;
if (do_padding) {
cout << "Enter p to stop padding." << endl;
} else {
cout << "Enter p to restart padding." << endl;
}
control->toggle_padding();
} else if (cmd[0] == "q") {
raise(SIGTERM);
} else if (cmd[0] == "cell_gain") {
if (cmd.size() != 3) {
cout << "Usage: " << cmd[0] << " [cell identifier] [gain in dB]" << endl;
continue;
}
// Parse command arguments
uint32_t cell_id = srsran::string_cast<uint32_t>(cmd[1]);
float gain_db = srsran::string_cast<float>(cmd[2]);
// Set cell gain
control->cmd_cell_gain(cell_id, gain_db);
} else {
cout << "Available commands: " << endl;
cout << " t: starts console trace" << endl;
cout << " q: quit srsenb" << endl;
cout << " cell_gain: set relative cell gain" << endl;
cout << " p: starts MAC padding" << endl;
cout << endl;
list<string> cmd_list;
srsran::string_parse_list(input_line, ';', cmd_list);
for (const string& cmd : cmd_list) {
execute_cmd(metrics, control, cmd);
}
}
}

@ -235,7 +235,7 @@ bool enb_stack_lte::get_metrics(stack_metrics_t* metrics)
void enb_stack_lte::run_thread()
{
while (started) {
while (started.load(std::memory_order_relaxed)) {
task_sched.run_next_task();
}
}

@ -174,7 +174,7 @@ void mac::phy_config_enabled(uint16_t rnti, bool enabled)
}
// Update UE configuration
int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
int mac::ue_cfg(uint16_t rnti, const sched_interface::ue_cfg_t* cfg)
{
srsran::rwlock_read_guard lock(rwlock);
if (not check_ue_active(rnti)) {
@ -186,10 +186,12 @@ int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
ue_ptr->start_ta();
// Update Scheduler configuration
if (cfg != nullptr and scheduler.ue_cfg(rnti, *cfg) == SRSRAN_ERROR) {
logger.error("Registering new UE rnti=0x%x to SCHED", rnti);
if (scheduler.ue_cfg(rnti, *cfg) == SRSRAN_ERROR) {
logger.error("Registering UE rnti=0x%x to SCHED", rnti);
return SRSRAN_ERROR;
}
ue_ptr->ue_cfg(*cfg);
return SRSRAN_SUCCESS;
}
@ -220,7 +222,7 @@ int mac::ue_rem(uint16_t rnti)
}
// Called after Msg3
int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg)
int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface::ue_cfg_t& cfg)
{
srsran::rwlock_read_guard lock(rwlock);
if (temp_crnti != crnti) {
@ -230,7 +232,7 @@ int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_c
// Schedule ConRes Msg4
scheduler.dl_mac_buffer_state(crnti, (uint32_t)srsran::dl_sch_lcid::CON_RES_ID);
}
return ue_cfg(crnti, cfg);
return ue_cfg(crnti, &cfg);
}
int mac::cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg_)
@ -323,14 +325,7 @@ int mac::push_pdu(uint32_t tti_rx,
return SRSRAN_ERROR;
}
std::array<int, SRSRAN_MAX_CARRIERS> enb_ue_cc_map = scheduler.get_enb_ue_cc_map(rnti);
if (enb_ue_cc_map[enb_cc_idx] < 0) {
logger.error("User rnti=0x%x is not activated for carrier %d", rnti, enb_cc_idx);
return SRSRAN_ERROR;
}
uint32_t ue_cc_idx = enb_ue_cc_map[enb_cc_idx];
srsran::unique_byte_buffer_t pdu = ue_db[rnti]->release_pdu(tti_rx, ue_cc_idx);
srsran::unique_byte_buffer_t pdu = ue_db[rnti]->release_pdu(tti_rx, enb_cc_idx);
if (pdu == nullptr) {
logger.warning("Could not find MAC UL PDU for rnti=0x%x, cc=%d, tti=%d", rnti, enb_cc_idx, tti_rx);
return SRSRAN_ERROR;
@ -463,7 +458,7 @@ bool mac::is_valid_rnti_unprotected(uint16_t rnti)
return true;
}
uint16_t mac::allocate_ue()
uint16_t mac::allocate_ue(uint32_t enb_cc_idx)
{
ue* inserted_ue = nullptr;
uint16_t rnti = SRSRAN_INVALID_RNTI;
@ -482,7 +477,7 @@ uint16_t mac::allocate_ue()
// Allocate and initialize UE object
unique_rnti_ptr<ue> ue_ptr = make_rnti_obj<ue>(
rnti, rnti, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get());
rnti, rnti, enb_cc_idx, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get());
// Add UE to rnti map
srsran::rwlock_write_guard rw_lock(rwlock);
@ -509,19 +504,17 @@ uint16_t mac::allocate_ue()
return rnti;
}
uint16_t mac::reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg)
uint16_t mac::reserve_new_crnti(const sched_interface::ue_cfg_t& uecfg)
{
uint16_t rnti = allocate_ue();
uint16_t rnti = allocate_ue(uecfg.supported_cc_list[0].enb_cc_idx);
if (rnti == SRSRAN_INVALID_RNTI) {
return rnti;
}
// Add new user to the scheduler so that it can RX/TX SRB0
if (scheduler.ue_cfg(rnti, ue_cfg) != SRSRAN_SUCCESS) {
logger.error("Registering new user rnti=0x%x to SCHED", rnti);
if (ue_cfg(rnti, &uecfg) != SRSRAN_SUCCESS) {
return SRSRAN_INVALID_RNTI;
}
return rnti;
}
@ -532,7 +525,7 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx
auto rach_tprof_meas = rach_tprof.start();
stack_task_queue.push([this, tti, enb_cc_idx, preamble_idx, time_adv, rach_tprof_meas]() mutable {
uint16_t rnti = allocate_ue();
uint16_t rnti = allocate_ue(enb_cc_idx);
if (rnti == SRSRAN_INVALID_RNTI) {
return;
}
@ -550,20 +543,18 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx
++detected_rachs[enb_cc_idx];
// Add new user to the scheduler so that it can RX/TX SRB0
sched_interface::ue_cfg_t ue_cfg = {};
ue_cfg.supported_cc_list.emplace_back();
ue_cfg.supported_cc_list.back().active = true;
ue_cfg.supported_cc_list.back().enb_cc_idx = enb_cc_idx;
ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
ue_cfg.supported_cc_list[0].dl_cfg.tm = SRSRAN_TM1;
if (scheduler.ue_cfg(rnti, ue_cfg) != SRSRAN_SUCCESS) {
logger.error("Registering new user rnti=0x%x to SCHED", rnti);
ue_rem(rnti);
sched_interface::ue_cfg_t uecfg = {};
uecfg.supported_cc_list.emplace_back();
uecfg.supported_cc_list.back().active = true;
uecfg.supported_cc_list.back().enb_cc_idx = enb_cc_idx;
uecfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
uecfg.supported_cc_list[0].dl_cfg.tm = SRSRAN_TM1;
if (ue_cfg(rnti, &uecfg) != SRSRAN_SUCCESS) {
return;
}
// Register new user in RRC
if (rrc_h->add_user(rnti, ue_cfg) == SRSRAN_ERROR) {
if (rrc_h->add_user(rnti, uecfg) == SRSRAN_ERROR) {
ue_rem(rnti);
return;
}
@ -621,7 +612,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list)
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
dl_sched_res->pdsch[n].softbuffer_tx[tb] =
ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.ue_cc_idx, sched_result.data[i].dci.pid, tb);
ue_db[rnti]->get_tx_softbuffer(enb_cc_idx, sched_result.data[i].dci.pid, tb);
// If the Rx soft-buffer is not given, abort transmission
if (dl_sched_res->pdsch[n].softbuffer_tx[tb] == nullptr) {
@ -630,7 +621,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list)
if (sched_result.data[i].nof_pdu_elems[tb] > 0) {
/* Get PDU if it's a new transmission */
dl_sched_res->pdsch[n].data[tb] = ue_db[rnti]->generate_pdu(sched_result.data[i].dci.ue_cc_idx,
dl_sched_res->pdsch[n].data[tb] = ue_db[rnti]->generate_pdu(enb_cc_idx,
sched_result.data[i].dci.pid,
tb,
sched_result.data[i].pdu[tb],
@ -936,11 +927,11 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list)
phy_ul_sched_res->pusch[n].pid = TTI_RX(tti_tx_ul) % SRSRAN_FDD_NOF_HARQ;
phy_ul_sched_res->pusch[n].needs_pdcch = sched_result.pusch[i].needs_pdcch;
phy_ul_sched_res->pusch[n].dci = sched_result.pusch[i].dci;
phy_ul_sched_res->pusch[n].softbuffer_rx =
ue_db[rnti]->get_rx_softbuffer(sched_result.pusch[i].dci.ue_cc_idx, tti_tx_ul);
phy_ul_sched_res->pusch[n].softbuffer_rx = ue_db[rnti]->get_rx_softbuffer(enb_cc_idx, tti_tx_ul);
// If the Rx soft-buffer is not given, abort reception
if (phy_ul_sched_res->pusch[n].softbuffer_rx == nullptr) {
logger.warning("Failed to retrieve UL softbuffer for tti=%d, cc=%d", tti_tx_ul, enb_cc_idx);
continue;
}
@ -948,7 +939,7 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list)
srsran_softbuffer_rx_reset_tbs(phy_ul_sched_res->pusch[n].softbuffer_rx, sched_result.pusch[i].tbs * 8);
}
phy_ul_sched_res->pusch[n].data =
ue_db[rnti]->request_buffer(tti_tx_ul, sched_result.pusch[i].dci.ue_cc_idx, sched_result.pusch[i].tbs);
ue_db[rnti]->request_buffer(tti_tx_ul, enb_cc_idx, sched_result.pusch[i].tbs);
if (phy_ul_sched_res->pusch[n].data) {
phy_ul_sched_res->nof_grants++;
} else {
@ -995,7 +986,7 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_,
memcpy(mcch_payload_buffer, mcch_payload, mcch_payload_length * sizeof(uint8_t));
current_mcch_length = mcch_payload_length;
ue_db[SRSRAN_MRNTI] = std::unique_ptr<ue>{
new ue(SRSRAN_MRNTI, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())};
new ue(SRSRAN_MRNTI, 0, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())};
rrc_h->add_user(SRSRAN_MRNTI, {});
}

@ -276,18 +276,22 @@ std::array<int, SRSRAN_MAX_CARRIERS> sched::get_enb_ue_cc_map(uint16_t rnti)
return ret;
}
std::array<bool, SRSRAN_MAX_CARRIERS> sched::get_scell_activation_mask(uint16_t rnti)
{
std::array<bool, SRSRAN_MAX_CARRIERS> scell_mask = {};
ue_db_access_locked(rnti, [this, &scell_mask](sched_ue& ue) {
for (size_t enb_cc_idx = 0; enb_cc_idx < carrier_schedulers.size(); ++enb_cc_idx) {
const sched_ue_cell* cc_ue = ue.find_ue_carrier(enb_cc_idx);
if (cc_ue != nullptr and (cc_ue->cc_state() == cc_st::active or cc_ue->cc_state() == cc_st::activating)) {
scell_mask[cc_ue->get_ue_cc_idx()] = true;
}
}
});
return scell_mask;
std::array<int, SRSRAN_MAX_CARRIERS> sched::get_enb_ue_activ_cc_map(uint16_t rnti)
{
std::array<int, SRSRAN_MAX_CARRIERS> ret{};
ret.fill(-1); // -1 for inactive & non-existent carriers
ue_db_access_locked(
rnti,
[this, &ret](sched_ue& ue) {
for (size_t enb_cc_idx = 0; enb_cc_idx < carrier_schedulers.size(); ++enb_cc_idx) {
const sched_ue_cell* cc_ue = ue.find_ue_carrier(enb_cc_idx);
if (cc_ue != nullptr and (cc_ue->cc_state() == cc_st::active or cc_ue->cc_state() == cc_st::activating)) {
ret[enb_cc_idx] = cc_ue->get_ue_cc_idx();
}
}
},
__PRETTY_FUNCTION__);
return ret;
}
/*******************************************************

@ -198,8 +198,8 @@ int generate_ra_bc_dci_format1a_common(srsran_dci_dl_t& dci,
const sched_cell_params_t& cell_params,
uint32_t current_cfi)
{
static const uint32_t Qm = 2, bc_rar_cqi = 4;
static const float max_ctrl_coderate = std::min(srsran_cqi_to_coderate(bc_rar_cqi + 1, false), 0.932F * Qm);
static const uint32_t Qm = 2;
static const float max_ctrl_coderate = std::min(cell_params.sched_cfg->max_sib_coderate, 0.932F * Qm);
// Calculate I_tbs for this TBS
int tbs = static_cast<int>(req_bytes) * 8;

@ -57,10 +57,8 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg
fixed_mcs_ul(cell_cfg_.sched_cfg->pusch_mcs),
current_tti(current_tti_),
max_aggr_level(cell_cfg_.sched_cfg->max_aggr_level >= 0 ? cell_cfg_.sched_cfg->max_aggr_level : 3),
dl_cqi_ctxt(cell_cfg_.nof_prb(), 0, 1)
dl_cqi_ctxt(cell_cfg_.nof_prb(), 0, cell_cfg_.sched_cfg->init_dl_cqi)
{
clear_feedback();
float target_bler = cell_cfg->sched_cfg->target_bler;
delta_inc = cell_cfg->sched_cfg->adaptive_link_step_size; // delta_{down} of OLLA
delta_dec = (1 - target_bler) * delta_inc / target_bler;
@ -166,7 +164,7 @@ void sched_ue_cell::clear_feedback()
dl_ri_tti_rx = tti_point{};
dl_pmi = 0;
dl_pmi_tti_rx = tti_point{};
dl_cqi_ctxt.reset_cqi(ue_cc_idx == 0 ? cell_cfg->cfg.initial_dl_cqi : 1);
dl_cqi_ctxt.reset_cqi(ue_cc_idx == 0 ? cell_cfg->sched_cfg->init_dl_cqi : 1);
ul_cqi_tti_rx = tti_point{};
}

@ -182,7 +182,7 @@ void cc_buffer_handler::reset()
}
ue::ue(uint16_t rnti_,
uint32_t nof_prb_,
uint32_t enb_cc_idx,
sched_interface* sched_,
rrc_interface_mac* rrc_,
rlc_interface_mac* rlc_,
@ -204,7 +204,7 @@ ue::ue(uint16_t rnti_,
cc_buffers(nof_cells_)
{
// Allocate buffer for PCell
cc_buffers[0].allocate_cc(softbuffer_pool->make());
cc_buffers[enb_cc_idx].allocate_cc(softbuffer_pool->make());
}
ue::~ue() {}
@ -229,31 +229,41 @@ void ue::start_pcap(srsran::mac_pcap* pcap_)
pcap = pcap_;
}
srsran_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t ue_cc_idx, uint32_t tti)
void ue::ue_cfg(const sched_interface::ue_cfg_t& ue_cfg)
{
if ((size_t)ue_cc_idx >= cc_buffers.size()) {
ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size());
for (const auto& ue_cc : ue_cfg.supported_cc_list) {
// Allocate and initialize Rx/Tx softbuffers for new carriers (exclude PCell)
if (ue_cc.active and cc_buffers[ue_cc.enb_cc_idx].empty()) {
cc_buffers[ue_cc.enb_cc_idx].allocate_cc(softbuffer_pool->make());
}
}
}
srsran_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t enb_cc_idx, uint32_t tti)
{
if ((size_t)enb_cc_idx >= cc_buffers.size() or cc_buffers[enb_cc_idx].empty()) {
ERROR("eNB CC Index (%d/%zd) out-of-range", enb_cc_idx, cc_buffers.size());
return nullptr;
}
return &cc_buffers[ue_cc_idx].get_rx_softbuffer(tti);
return &cc_buffers[enb_cc_idx].get_rx_softbuffer(tti);
}
srsran_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t ue_cc_idx, uint32_t harq_process, uint32_t tb_idx)
srsran_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t enb_cc_idx, uint32_t harq_process, uint32_t tb_idx)
{
if ((size_t)ue_cc_idx >= cc_buffers.size()) {
ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size());
if ((size_t)enb_cc_idx >= cc_buffers.size() or cc_buffers[enb_cc_idx].empty()) {
ERROR("eNB CC Index (%d/%zd) out-of-range", enb_cc_idx, cc_buffers.size());
return nullptr;
}
return &cc_buffers[ue_cc_idx].get_tx_softbuffer(harq_process, tb_idx);
return &cc_buffers[enb_cc_idx].get_tx_softbuffer(harq_process, tb_idx);
}
uint8_t* ue::request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len)
uint8_t* ue::request_buffer(uint32_t tti, uint32_t enb_cc_idx, uint32_t len)
{
srsran_assert(len > 0, "UE buffers: Requesting buffer for zero bytes");
std::unique_lock<std::mutex> lock(rx_buffers_mutex);
return cc_buffers[ue_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len);
return cc_buffers[enb_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len);
}
void ue::clear_old_buffers(uint32_t tti)
@ -386,10 +396,10 @@ void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs)
logger.debug("MAC PDU processed");
}
srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t ue_cc_idx)
srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t enb_cc_idx)
{
std::lock_guard<std::mutex> lock(rx_buffers_mutex);
return cc_buffers[ue_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti));
return cc_buffers[enb_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti));
}
bool ue::process_ce(srsran::sch_subh* subh, uint32_t grant_nof_prbs)
@ -509,15 +519,15 @@ void ue::allocate_ce(srsran::sch_pdu* pdu, uint32_t lcid)
break;
case srsran::dl_sch_lcid::SCELL_ACTIVATION:
if (pdu->new_subh()) {
std::array<bool, SRSRAN_MAX_CARRIERS> active_scell_list = sched->get_scell_activation_mask(rnti);
std::array<int, SRSRAN_MAX_CARRIERS> active_ccs = sched->get_enb_ue_activ_cc_map(rnti);
std::array<bool, SRSRAN_MAX_CARRIERS> active_scell_list{};
for (int ue_cc_idx : active_ccs) {
if (ue_cc_idx > 0) {
active_scell_list[ue_cc_idx] = true;
}
}
if (pdu->get()->set_scell_activation_cmd(active_scell_list)) {
phy->set_activation_deactivation_scell(rnti, active_scell_list);
// Allocate and initialize Rx/Tx softbuffers for new carriers (exclude PCell)
for (size_t i = 0; i < std::min(active_scell_list.size(), cc_buffers.size()); ++i) {
if (active_scell_list[i] and cc_buffers[i].empty()) {
cc_buffers[i].allocate_cc(softbuffer_pool->make());
}
}
} else {
logger.error("CE: Setting SCell Activation CE");
}
@ -531,7 +541,7 @@ void ue::allocate_ce(srsran::sch_pdu* pdu, uint32_t lcid)
}
}
uint8_t* ue::generate_pdu(uint32_t ue_cc_idx,
uint8_t* ue::generate_pdu(uint32_t enb_cc_idx,
uint32_t harq_pid,
uint32_t tb_idx,
const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
@ -540,30 +550,26 @@ uint8_t* ue::generate_pdu(uint32_t ue_cc_idx,
{
std::lock_guard<std::mutex> lock(mutex);
uint8_t* ret = nullptr;
if (rlc) {
if (ue_cc_idx < SRSRAN_MAX_CARRIERS && harq_pid < SRSRAN_FDD_NOF_HARQ && tb_idx < SRSRAN_MAX_TB) {
srsran::byte_buffer_t* buffer = cc_buffers[ue_cc_idx].get_tx_payload_buffer(harq_pid, tb_idx);
buffer->clear();
mac_msg_dl.init_tx(buffer, grant_size, false);
for (uint32_t i = 0; i < nof_pdu_elems; i++) {
if (pdu[i].lcid <= (uint32_t)srsran::ul_sch_lcid::PHR_REPORT) {
allocate_sdu(&mac_msg_dl, pdu[i].lcid, pdu[i].nbytes);
} else {
allocate_ce(&mac_msg_dl, pdu[i].lcid);
}
}
ret = mac_msg_dl.write_packet(logger);
if (logger.info.enabled()) {
fmt::memory_buffer str_buffer;
mac_msg_dl.to_string(str_buffer);
logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer));
if (enb_cc_idx < SRSRAN_MAX_CARRIERS && harq_pid < SRSRAN_FDD_NOF_HARQ && tb_idx < SRSRAN_MAX_TB) {
srsran::byte_buffer_t* buffer = cc_buffers[enb_cc_idx].get_tx_payload_buffer(harq_pid, tb_idx);
buffer->clear();
mac_msg_dl.init_tx(buffer, grant_size, false);
for (uint32_t i = 0; i < nof_pdu_elems; i++) {
if (pdu[i].lcid <= (uint32_t)srsran::ul_sch_lcid::PHR_REPORT) {
allocate_sdu(&mac_msg_dl, pdu[i].lcid, pdu[i].nbytes);
} else {
allocate_ce(&mac_msg_dl, pdu[i].lcid);
}
} else {
logger.error(
"Invalid parameters calling generate_pdu: cc_idx=%d, harq_pid=%d, tb_idx=%d", ue_cc_idx, harq_pid, tb_idx);
}
ret = mac_msg_dl.write_packet(logger);
if (logger.info.enabled()) {
fmt::memory_buffer str_buffer;
mac_msg_dl.to_string(str_buffer);
logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer));
}
} else {
std::cout << "Error ue not configured (must call config() first" << std::endl;
logger.error(
"Invalid parameters calling generate_pdu: cc_idx=%d, harq_pid=%d, tb_idx=%d", enb_cc_idx, harq_pid, tb_idx);
}
return ret;
}

@ -20,6 +20,10 @@
*/
#include "srsenb/hdr/stack/ngap/ngap.h"
#include "srsran/common/int_helpers.h"
using srsran::s1ap_mccmnc_to_plmn;
using srsran::uint32_to_uint8;
#define procError(fmt, ...) ngap_ptr->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procWarning(fmt, ...) ngap_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
@ -154,20 +158,137 @@ bool ngap::is_amf_connected()
}
// Generate common NGAP protocol IEs from config args
void ngap::build_tai_cgi()
int ngap::build_tai_cgi()
{
uint32_t plmn;
uint8_t shift;
// TAI
srsran::s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn);
tai.plmn_id.from_number(plmn);
tai.tac.from_number(args.tac);
// nr_cgi
// NR CGI
nr_cgi.plmn_id.from_number(plmn);
// TODO Check how to build nr cell id
nr_cgi.nrcell_id.from_number((uint32_t)(args.gnb_id << 8) | args.cell_id);
// NR CELL ID (36 bits) = gnb_id (22...32 bits) + cell_id (4...14 bits)
if (((uint8_t)log2(args.gnb_id) + (uint8_t)log2(args.cell_id) + 2) > 36) {
logger.error("gNB ID and Cell ID combination greater than 36 bits");
return SRSRAN_ERROR;
}
// Consider moving sanity checks into the parsing function of the configs.
if (((uint8_t)log2(args.gnb_id) + 1) < 22) {
shift = 14;
} else {
shift = 36 - ((uint8_t)log2(args.gnb_id) + 1);
}
nr_cgi.nrcell_id.from_number((uint64_t)args.gnb_id << shift | args.cell_id);
return SRSRAN_SUCCESS;
}
/*******************************************************************************
/* RRC interface
********************************************************************************/
void ngap::initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu)
{
std::unique_ptr<ue> ue_ptr{new ue{this}};
ue_ptr->ctxt.rnti = rnti;
ue_ptr->ctxt.gnb_cc_idx = gnb_cc_idx;
ue* u = users.add_user(std::move(ue_ptr));
if (u == nullptr) {
logger.error("Failed to add rnti=0x%x", rnti);
return;
}
u->send_initialuemessage(cause, std::move(pdu), false);
}
void ngap::initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu,
uint32_t s_tmsi)
{
std::unique_ptr<ue> ue_ptr{new ue{this}};
ue_ptr->ctxt.rnti = rnti;
ue_ptr->ctxt.gnb_cc_idx = gnb_cc_idx;
ue* u = users.add_user(std::move(ue_ptr));
if (u == nullptr) {
logger.error("Failed to add rnti=0x%x", rnti);
return;
}
u->send_initialuemessage(cause, std::move(pdu), true, s_tmsi);
}
void ngap::ue_ctxt_setup_complete(uint16_t rnti)
{
ue* u = users.find_ue_rnti(rnti);
if (u == nullptr) {
return;
}
u->ue_ctxt_setup_complete();
}
/*********************************************************
* ngap::user_list class
*********************************************************/
ngap::ue* ngap::user_list::find_ue_rnti(uint16_t rnti)
{
if (rnti == SRSRAN_INVALID_RNTI) {
return nullptr;
}
auto it = std::find_if(
users.begin(), users.end(), [rnti](const user_list::pair_type& v) { return v.second->ctxt.rnti == rnti; });
return it != users.end() ? it->second.get() : nullptr;
}
ngap::ue* ngap::user_list::find_ue_gnbid(uint32_t gnbid)
{
auto it = users.find(gnbid);
return (it != users.end()) ? it->second.get() : nullptr;
}
ngap::ue* ngap::user_list::find_ue_amfid(uint32_t amfid)
{
auto it = std::find_if(users.begin(), users.end(), [amfid](const user_list::pair_type& v) {
return v.second->ctxt.amf_ue_ngap_id == amfid;
});
return it != users.end() ? it->second.get() : nullptr;
}
ngap::ue* ngap::user_list::add_user(std::unique_ptr<ngap::ue> user)
{
static srslog::basic_logger& logger = srslog::fetch_basic_logger("NGAP");
// Check for ID repetitions
if (find_ue_rnti(user->ctxt.rnti) != nullptr) {
logger.error("The user to be added with rnti=0x%x already exists", user->ctxt.rnti);
return nullptr;
}
if (find_ue_gnbid(user->ctxt.ran_ue_ngap_id) != nullptr) {
logger.error("The user to be added with ran ue ngap id=%d already exists", user->ctxt.ran_ue_ngap_id);
return nullptr;
}
if (user->ctxt.amf_ue_ngap_id.has_value() and find_ue_amfid(user->ctxt.amf_ue_ngap_id.value()) != nullptr) {
logger.error("The user to be added with amf id=%d already exists", user->ctxt.amf_ue_ngap_id.value());
return nullptr;
}
auto p = users.insert(std::make_pair(user->ctxt.ran_ue_ngap_id, std::move(user)));
return p.second ? p.first->second.get() : nullptr;
}
void ngap::user_list::erase(ue* ue_ptr)
{
static srslog::basic_logger& logger = srslog::fetch_basic_logger("NGAP");
auto it = users.find(ue_ptr->ctxt.ran_ue_ngap_id);
if (it == users.end()) {
logger.error("User to be erased does not exist");
return;
}
users.erase(it);
}
/*******************************************************************************
@ -200,11 +321,11 @@ bool ngap::handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu,
amf_socket.close();
}
// Restart MME connection procedure if we lost connection
// Restart AMF connection procedure if we lost connection
if (not amf_socket.is_open()) {
amf_connected = false;
if (ngsetup_proc.is_busy()) {
logger.error("Failed to initiate MME connection procedure, as it is already running.");
logger.error("Failed to initiate AMF connection procedure, as it is already running.");
return false;
}
ngsetup_proc.launch();
@ -217,6 +338,7 @@ bool ngap::handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu,
bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu)
{
// TODO:
// Save message to PCAP
// if (pcap != nullptr) {
// pcap->write_ngap(pdu->msg, pdu->N_bytes);
@ -229,18 +351,19 @@ bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu)
logger.error(pdu->msg, pdu->N_bytes, "Failed to unpack received PDU");
cause_c cause;
cause.set_protocol().value = cause_protocol_opts::transfer_syntax_error;
// send_error_indication(cause);
send_error_indication(cause);
return false;
}
// TODO:
// log_ngap_msg(rx_pdu, srsran::make_span(*pdu), true);
switch (rx_pdu.type().value) {
// case ngap_pdu_c::types_opts::init_msg:
// return handle_initiatingmessage(rx_pdu.init_msg());
case ngap_pdu_c::types_opts::init_msg:
return handle_initiatingmessage(rx_pdu.init_msg());
case ngap_pdu_c::types_opts::successful_outcome:
return handle_successfuloutcome(rx_pdu.successful_outcome());
// case ngap_pdu_c::types_opts::unsuccessful_outcome:
// return handle_unsuccessfuloutcome(rx_pdu.unsuccessful_outcome());
case ngap_pdu_c::types_opts::unsuccessful_outcome:
return handle_unsuccessfuloutcome(rx_pdu.unsuccessful_outcome());
default:
logger.error("Unhandled PDU type %d", rx_pdu.type().value);
return false;
@ -249,6 +372,19 @@ bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu)
return true;
}
bool ngap::handle_initiatingmessage(const asn1::ngap_nr::init_msg_s& msg)
{
switch (msg.value.type().value) {
case ngap_elem_procs_o::init_msg_c::types_opts::dl_nas_transport:
return handle_dlnastransport(msg.value.dl_nas_transport());
case ngap_elem_procs_o::init_msg_c::types_opts::init_context_setup_request:
return handle_initialctxtsetuprequest(msg.value.init_context_setup_request());
default:
logger.error("Unhandled initiating message: %s", msg.value.type().to_string());
}
return true;
}
bool ngap::handle_successfuloutcome(const successful_outcome_s& msg)
{
switch (msg.value.type().value) {
@ -260,6 +396,17 @@ bool ngap::handle_successfuloutcome(const successful_outcome_s& msg)
return true;
}
bool ngap::handle_unsuccessfuloutcome(const asn1::ngap_nr::unsuccessful_outcome_s& msg)
{
switch (msg.value.type().value) {
case ngap_elem_procs_o::unsuccessful_outcome_c::types_opts::ng_setup_fail:
return handle_ngsetupfailure(msg.value.ng_setup_fail());
default:
logger.error("Unhandled unsuccessful outcome message: %s", msg.value.type().to_string());
}
return true;
}
bool ngap::handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg)
{
ngsetupresponse = msg;
@ -267,6 +414,93 @@ bool ngap::handle_ngsetupresponse(const asn1::ngap_nr::ng_setup_resp_s& msg)
ng_setup_proc_t::ngsetupresult res;
res.success = true;
ngsetup_proc.trigger(res);
return true;
}
bool ngap::handle_ngsetupfailure(const asn1::ngap_nr::ng_setup_fail_s& msg)
{
std::string cause = get_cause(msg.protocol_ies.cause.value);
logger.error("NG Setup Failure. Cause: %s", cause.c_str());
srsran::console("NG Setup Failure. Cause: %s\n", cause.c_str());
return true;
}
bool ngap::handle_dlnastransport(const asn1::ngap_nr::dl_nas_transport_s& msg)
{
if (msg.ext) {
logger.warning("Not handling NGAP message extension");
}
ue* u =
handle_ngapmsg_ue_id(msg.protocol_ies.ran_ue_ngap_id.value.value, msg.protocol_ies.amf_ue_ngap_id.value.value);
if (u == nullptr) {
return false;
}
if (msg.protocol_ies.old_amf_present) {
logger.warning("Not handling OldAMF");
}
if (msg.protocol_ies.ran_paging_prio_present) {
logger.warning("Not handling RANPagingPriority");
}
if (msg.protocol_ies.mob_restrict_list_present) {
logger.warning("Not handling MobilityRestrictionList");
}
if (msg.protocol_ies.idx_to_rfsp_present) {
logger.warning("Not handling IndexToRFSP");
}
if (msg.protocol_ies.ue_aggregate_maximum_bit_rate_present) {
logger.warning("Not handling UEAggregateMaximumBitRate");
}
if (msg.protocol_ies.allowed_nssai_present) {
logger.warning("Not handling AllowedNSSAI");
}
// TODO: Pass NAS PDU once RRC interface is ready
/* srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Fatal Error: Couldn't allocate buffer in ngap::run_thread().");
return false;
}
memcpy(pdu->msg, msg.protocol_ies.nas_pdu.value.data(), msg.protocol_ies.nas_pdu.value.size());
pdu->N_bytes = msg.protocol_ies.nas_pdu.value.size();
rrc->write_dl_info(u->ctxt.rnti, std::move(pdu)); */
return true;
}
bool ngap::handle_initialctxtsetuprequest(const asn1::ngap_nr::init_context_setup_request_s& msg)
{
ue* u =
handle_ngapmsg_ue_id(msg.protocol_ies.ran_ue_ngap_id.value.value, msg.protocol_ies.amf_ue_ngap_id.value.value);
if (u == nullptr) {
return false;
}
u->ctxt.amf_pointer = msg.protocol_ies.guami.value.amf_pointer.to_number();
u->ctxt.amf_set_id = msg.protocol_ies.guami.value.amf_set_id.to_number();
u->ctxt.amf_region_id = msg.protocol_ies.guami.value.amf_region_id.to_number();
// Setup UE ctxt in RRC once interface is ready
/* if (not rrc->setup_ue_ctxt(u->ctxt.rnti, msg)) {
return false;
} */
/* if (msg.protocol_ies.nas_pdu_present) {
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Fatal Error: Couldn't allocate buffer in ngap::run_thread().");
return false;
}
memcpy(pdu->msg, msg.protocol_ies.nas_pdu.value.data(), msg.protocol_ies.nas_pdu.value.size());
pdu->N_bytes = msg.protocol_ies.nas_pdu.value.size();
rrc->write_dl_info(u->ctxt.rnti, std::move(pdu));
} */
return true;
}
@ -353,6 +587,134 @@ bool ngap::setup_ng()
return sctp_send_ngap_pdu(pdu, 0, "ngSetupRequest");
}
/*******************************************************************************
/* NGAP message senders
********************************************************************************/
bool ngap::ue::send_initialuemessage(asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu,
bool has_tmsi,
uint32_t s_tmsi)
{
if (not ngap_ptr->amf_connected) {
return false;
}
ngap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_NGAP_NR_ID_INIT_UE_MSG);
init_ue_msg_ies_container& container = tx_pdu.init_msg().value.init_ue_msg().protocol_ies;
// 5G-S-TMSI
if (has_tmsi) {
container.five_g_s_tmsi_present = true;
srsran::uint32_to_uint8(s_tmsi, container.five_g_s_tmsi.value.five_g_tmsi.data());
container.five_g_s_tmsi.value.amf_set_id.from_number(ctxt.amf_set_id);
container.five_g_s_tmsi.value.amf_pointer.from_number(ctxt.amf_pointer);
}
// RAN_UE_NGAP_ID
container.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id;
// NAS_PDU
container.nas_pdu.value.resize(pdu->N_bytes);
memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes);
// RRC Establishment Cause
container.rrcestablishment_cause.value = cause;
// User Location Info
// userLocationInformationNR
container.user_location_info.value.set_user_location_info_nr();
container.user_location_info.value.user_location_info_nr().nr_cgi.nrcell_id = ngap_ptr->nr_cgi.nrcell_id;
container.user_location_info.value.user_location_info_nr().nr_cgi.plmn_id = ngap_ptr->nr_cgi.plmn_id;
container.user_location_info.value.user_location_info_nr().tai.plmn_id = ngap_ptr->tai.plmn_id;
container.user_location_info.value.user_location_info_nr().tai.tac = ngap_ptr->tai.tac;
return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "InitialUEMessage");
}
bool ngap::ue::send_ulnastransport(srsran::unique_byte_buffer_t pdu)
{
if (not ngap_ptr->amf_connected) {
return false;
}
ngap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_NGAP_NR_ID_UL_NAS_TRANSPORT);
asn1::ngap_nr::ul_nas_transport_ies_container& container = tx_pdu.init_msg().value.ul_nas_transport().protocol_ies;
// AMF UE NGAP ID
container.amf_ue_ngap_id.value = ctxt.amf_ue_ngap_id.value();
// RAN UE NGAP ID
container.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id;
// NAS PDU
container.nas_pdu.value.resize(pdu->N_bytes);
memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes);
// User Location Info
// userLocationInformationNR
container.user_location_info.value.set_user_location_info_nr();
container.user_location_info.value.user_location_info_nr().nr_cgi.nrcell_id = ngap_ptr->nr_cgi.nrcell_id;
container.user_location_info.value.user_location_info_nr().nr_cgi.plmn_id = ngap_ptr->nr_cgi.plmn_id;
container.user_location_info.value.user_location_info_nr().tai.plmn_id = ngap_ptr->tai.plmn_id;
container.user_location_info.value.user_location_info_nr().tai.tac = ngap_ptr->tai.tac;
return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "UplinkNASTransport");
}
void ngap::ue::ue_ctxt_setup_complete()
{
ngap_pdu_c tx_pdu;
// Handle PDU Session List once RRC interface is ready
tx_pdu.set_successful_outcome().load_info_obj(ASN1_NGAP_NR_ID_INIT_CONTEXT_SETUP);
auto& container = tx_pdu.successful_outcome().value.init_context_setup_resp().protocol_ies;
}
bool ngap::send_error_indication(const asn1::ngap_nr::cause_c& cause,
srsran::optional<uint32_t> ran_ue_ngap_id,
srsran::optional<uint32_t> amf_ue_ngap_id)
{
if (not amf_connected) {
return false;
}
ngap_pdu_c tx_pdu;
tx_pdu.set_init_msg().load_info_obj(ASN1_NGAP_NR_ID_ERROR_IND);
auto& container = tx_pdu.init_msg().value.error_ind().protocol_ies;
uint16_t rnti = SRSRAN_INVALID_RNTI;
container.ran_ue_ngap_id_present = ran_ue_ngap_id.has_value();
if (ran_ue_ngap_id.has_value()) {
container.ran_ue_ngap_id.value = ran_ue_ngap_id.value();
ue* user_ptr = users.find_ue_gnbid(ran_ue_ngap_id.value());
rnti = user_ptr != nullptr ? user_ptr->ctxt.rnti : SRSRAN_INVALID_RNTI;
}
container.amf_ue_ngap_id_present = amf_ue_ngap_id.has_value();
if (amf_ue_ngap_id.has_value()) {
container.amf_ue_ngap_id.value = amf_ue_ngap_id.value();
}
container.cause_present = true;
container.cause.value = cause;
return sctp_send_ngap_pdu(tx_pdu, rnti, "Error Indication");
}
/*******************************************************************************
/* ngap::ue Class
********************************************************************************/
ngap::ue::ue(ngap* ngap_ptr_) : ngap_ptr(ngap_ptr_)
{
ctxt.ran_ue_ngap_id = ngap_ptr->next_gnb_ue_ngap_id++;
gettimeofday(&ctxt.init_timestamp, nullptr);
stream_id = ngap_ptr->next_ue_stream_id;
}
/*******************************************************************************
/* General helpers
********************************************************************************/
@ -383,14 +745,14 @@ bool ngap::sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t
// }
if (rnti != SRSRAN_INVALID_RNTI) {
logger.info(buf->msg, buf->N_bytes, "Tx S1AP SDU, %s, rnti=0x%x", procedure_name, rnti);
logger.info(buf->msg, buf->N_bytes, "Tx NGAP SDU, %s, rnti=0x%x", procedure_name, rnti);
} else {
logger.info(buf->msg, buf->N_bytes, "Tx S1AP SDU, %s", procedure_name);
logger.info(buf->msg, buf->N_bytes, "Tx NGAP SDU, %s", procedure_name);
}
// TODO: when user list is ready
// uint16_t streamid = rnti == SRSRAN_INVALID_RNTI ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
uint16_t streamid = 0;
ssize_t n_sent = sctp_sendmsg(amf_socket.fd(),
uint16_t streamid = rnti == SRSRAN_INVALID_RNTI ? NONUE_STREAM_ID : users.find_ue_rnti(rnti)->stream_id;
ssize_t n_sent = sctp_sendmsg(amf_socket.fd(),
buf->msg,
buf->N_bytes,
(struct sockaddr*)&amf_addr,
@ -402,13 +764,87 @@ bool ngap::sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t
0);
if (n_sent == -1) {
if (rnti != SRSRAN_INVALID_RNTI) {
logger.error("Error: Failure at Tx S1AP SDU, %s, rnti=0x%x", procedure_name, rnti);
logger.error("Error: Failure at Tx NGAP SDU, %s, rnti=0x%x", procedure_name, rnti);
} else {
logger.error("Error: Failure at Tx S1AP SDU, %s", procedure_name);
logger.error("Error: Failure at Tx NGAP SDU, %s", procedure_name);
}
return false;
}
return true;
}
/**
* Helper method to find user based on the ran_ue_ngap_id stored in an S1AP Msg, and update amf_ue_ngap_id
* @param gnb_id ran_ue_ngap_id value stored in NGAP message
* @param amf_id amf_ue_ngap_id value stored in NGAP message
* @return pointer to user if it has been found
*/
ngap::ue* ngap::handle_ngapmsg_ue_id(uint32_t gnb_id, uint32_t amf_id)
{
ue* user_ptr = users.find_ue_gnbid(gnb_id);
ue* user_amf_ptr = nullptr;
cause_c cause;
// TODO: Introduce proper error handling for faulty ids
if (user_ptr != nullptr) {
if (user_ptr->ctxt.amf_ue_ngap_id == amf_id) {
return user_ptr;
}
user_amf_ptr = users.find_ue_amfid(amf_id);
if (not user_ptr->ctxt.amf_ue_ngap_id.has_value() and user_amf_ptr == nullptr) {
user_ptr->ctxt.amf_ue_ngap_id = amf_id;
return user_ptr;
}
logger.warning("AMF UE NGAP ID=%d not found - discarding message", amf_id);
if (user_amf_ptr != nullptr) {
cause.set_radio_network().value = cause_radio_network_opts::unknown_target_id;
}
} else {
user_amf_ptr = users.find_ue_amfid(amf_id);
logger.warning("RAN UE NGAP ID=%d not found - discarding message", gnb_id);
if (user_amf_ptr != nullptr) {
cause.set_radio_network().value = cause_radio_network_opts::unknown_local_ue_ngap_id;
}
}
send_error_indication(cause, gnb_id, amf_id);
if (user_ptr != nullptr) {
// rrc->release_ue(user_ptr->ctxt.rnti);
}
if (user_amf_ptr != nullptr and user_amf_ptr != user_ptr) {
// rrc->release_ue(user_mme_ptr->ctxt.rnti);
}
return nullptr;
}
std::string ngap::get_cause(const cause_c& c)
{
std::string cause = c.type().to_string();
cause += " - ";
switch (c.type().value) {
case cause_c::types_opts::radio_network:
cause += c.radio_network().to_string();
break;
case cause_c::types_opts::transport:
cause += c.transport().to_string();
break;
case cause_c::types_opts::nas:
cause += c.nas().to_string();
break;
case cause_c::types_opts::protocol:
cause += c.protocol().to_string();
break;
case cause_c::types_opts::misc:
cause += c.misc().to_string();
break;
default:
cause += "unknown";
break;
}
return cause;
}
} // namespace srsenb

@ -125,7 +125,7 @@ void mac_controller::handle_con_reject()
if (not crnti_set) {
crnti_set = true;
// Need to schedule ConRes CE for UE to see the Reject message
mac->ue_set_crnti(rnti, rnti, &current_sched_ue_cfg);
mac->ue_set_crnti(rnti, rnti, current_sched_ue_cfg);
}
}
@ -146,7 +146,7 @@ int mac_controller::handle_crnti_ce(uint32_t temp_crnti)
current_sched_ue_cfg.ue_bearers[i] = next_sched_ue_cfg.ue_bearers[i];
}
return mac->ue_set_crnti(temp_crnti, rnti, &current_sched_ue_cfg);
return mac->ue_set_crnti(temp_crnti, rnti, current_sched_ue_cfg);
}
int mac_controller::apply_basic_conn_cfg(const asn1::rrc::rr_cfg_ded_s& rr_cfg)
@ -192,7 +192,7 @@ int mac_controller::apply_basic_conn_cfg(const asn1::rrc::rr_cfg_ded_s& rr_cfg)
// In case of RRC Connection Setup/Reest message (Msg4), we need to resolve the contention by sending a ConRes CE
mac->phy_config_enabled(rnti, false);
crnti_set = true;
return mac->ue_set_crnti(rnti, rnti, &current_sched_ue_cfg);
return mac->ue_set_crnti(rnti, rnti, current_sched_ue_cfg);
}
void mac_controller::handle_con_setup_complete()
@ -292,7 +292,7 @@ void mac_controller::handle_intraenb_ho_cmd(const asn1::rrc::rrc_conn_recfg_r8_i
// Stop any SRB UL (including SRs)
for (uint32_t i = srb_to_lcid(lte_srb::srb1); i <= srb_to_lcid(lte_srb::srb2); ++i) {
next_sched_ue_cfg.ue_bearers[i].direction = sched_interface::ue_bearer_cfg_t::DL;
current_sched_ue_cfg.ue_bearers[i].direction = sched_interface::ue_bearer_cfg_t::DL;
}
update_mac(mac_controller::config_tx);

@ -655,7 +655,6 @@ void rrc::config_mac()
item.prach_freq_offset = cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset;
item.maxharq_msg3tx = cfg.sibs[1].sib2().rr_cfg_common.rach_cfg_common.max_harq_msg3_tx;
item.enable_64qam = cfg.sibs[1].sib2().rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.enable64_qam;
item.initial_dl_cqi = cfg.cell_list[ccidx].initial_dl_cqi;
item.target_pucch_ul_sinr = cfg.cell_list[ccidx].target_pucch_sinr_db;
item.target_pusch_ul_sinr = cfg.cell_list[ccidx].target_pusch_sinr_db;
item.enable_phr_handling = cfg.cell_list[ccidx].enable_phr_handling;
@ -857,8 +856,12 @@ void rrc::configure_mbsfn_sibs()
pmch_item->data_mcs = mbms_mcs;
pmch_item->mch_sched_period = srsran::pmch_info_t::mch_sched_period_t::rf64;
pmch_item->sf_alloc_end = 64 * 6;
phy->configure_mbsfn(&sibs2, &sibs13, mcch_t);
mac->write_mcch(&sibs2, &sibs13, &mcch_t, mcch_payload_buffer, current_mcch_length);
// Configure PHY when PHY is done being initialized
task_sched.defer_task([this, sibs2, sibs13, mcch_t]() mutable {
phy->configure_mbsfn(&sibs2, &sibs13, mcch_t);
mac->write_mcch(&sibs2, &sibs13, &mcch_t, mcch_payload_buffer, current_mcch_length);
});
}
int rrc::pack_mcch()

@ -23,6 +23,7 @@ add_subdirectory(phy)
add_subdirectory(upper)
add_subdirectory(rrc)
add_subdirectory(s1ap)
add_subdirectory(ngap)
add_executable(enb_metrics_test enb_metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc)
target_link_libraries(enb_metrics_test srsran_phy srsran_common)

@ -37,9 +37,9 @@ class mac_dummy : public mac_interface_rrc
{
public:
int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) override { return 0; }
int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override { return 0; }
int ue_cfg(uint16_t rnti, const sched_interface::ue_cfg_t* cfg) override { return 0; }
int ue_rem(uint16_t rnti) override { return 0; }
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override { return 0; }
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface::ue_cfg_t& cfg) override { return 0; }
int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg) override { return 0; }
int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) override { return 0; }
void phy_config_enabled(uint16_t rnti, bool enabled) override {}

@ -58,7 +58,6 @@ inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t no
cell_cfg.prach_freq_offset = (cell_cfg_phy.nof_prb == 6) ? 0 : 4;
cell_cfg.prach_rar_window = 3;
cell_cfg.maxharq_msg3tx = 3;
cell_cfg.initial_dl_cqi = 6;
cell_cfg.target_pusch_ul_sinr = -1;
cell_cfg.target_pucch_ul_sinr = -1;
cell_cfg.enable_phr_handling = false;

@ -0,0 +1,13 @@
#
# 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.
#
add_executable(ngap_test ngap_test.cc)
target_link_libraries(ngap_test srsran_common ngap_nr_asn1 srsenb_upper srsran_upper ngap_nr_asn1 srsgnb_upper srsgnb_ngap ${SCTP_LIBRARIES})
add_test(ngap_test ngap_test)

@ -0,0 +1,152 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsenb/hdr/stack/ngap/ngap.h"
#include "srsran/common/network_utils.h"
#include "srsran/common/test_common.h"
using namespace srsenb;
struct amf_dummy {
amf_dummy(const char* addr_str_, int port_) : addr_str(addr_str_), port(port_)
{
srsran::net_utils::set_sockaddr(&amf_sockaddr, addr_str, port);
{
using namespace srsran::net_utils;
fd = open_socket(addr_family::ipv4, socket_type::seqpacket, protocol_type::SCTP);
TESTASSERT(fd > 0);
TESTASSERT(bind_addr(fd, amf_sockaddr));
}
int success = listen(fd, SOMAXCONN);
srsran_assert(success == 0, "Failed to listen to incoming SCTP connections");
}
~amf_dummy()
{
if (fd > 0) {
close(fd);
}
}
srsran::unique_byte_buffer_t read_msg(sockaddr_in* sockfrom = nullptr)
{
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
sctp_sndrcvinfo sri = {};
int flags = 0;
ssize_t n_recv = sctp_recvmsg(fd, pdu->msg, pdu->get_tailroom(), (struct sockaddr*)&from, &fromlen, &sri, &flags);
if (n_recv > 0) {
if (sockfrom != nullptr) {
*sockfrom = from;
}
pdu->N_bytes = n_recv;
}
return pdu;
}
const char* addr_str;
int port;
struct sockaddr_in amf_sockaddr = {};
int fd;
srsran::unique_byte_buffer_t last_sdu;
};
struct dummy_socket_manager : public srsran::socket_manager_itf {
dummy_socket_manager() : srsran::socket_manager_itf(srslog::fetch_basic_logger("TEST")) {}
/// Register (fd, callback). callback is called within socket thread when fd has data.
bool add_socket_handler(int fd, recv_callback_t handler) final
{
if (s1u_fd > 0) {
return false;
}
s1u_fd = fd;
callback = std::move(handler);
return true;
}
/// remove registered socket fd
bool remove_socket(int fd) final
{
if (s1u_fd < 0) {
return false;
}
s1u_fd = -1;
return true;
}
int s1u_fd;
recv_callback_t callback;
};
void run_ng_setup(ngap& ngap_obj, amf_dummy& amf)
{
asn1::ngap_nr::ngap_pdu_c ngap_pdu;
// gNB -> AMF: NG Setup Request
srsran::unique_byte_buffer_t sdu = amf.read_msg();
TESTASSERT(sdu->N_bytes > 0);
asn1::cbit_ref cbref(sdu->msg, sdu->N_bytes);
TESTASSERT(ngap_pdu.unpack(cbref) == asn1::SRSASN_SUCCESS);
TESTASSERT(ngap_pdu.type().value == asn1::ngap_nr::ngap_pdu_c::types_opts::init_msg);
TESTASSERT(ngap_pdu.init_msg().proc_code == ASN1_NGAP_NR_ID_NG_SETUP);
// AMF -> gNB: ng Setup Response
sockaddr_in amf_addr = {};
sctp_sndrcvinfo rcvinfo = {};
int flags = 0;
uint8_t ng_setup_resp[] = {0x20, 0x15, 0x00, 0x55, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x31, 0x17, 0x00, 0x61, 0x6d,
0x61, 0x72, 0x69, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x61, 0x6d, 0x66, 0x2e, 0x35, 0x67, 0x63,
0x2e, 0x6d, 0x6e, 0x63, 0x30, 0x30, 0x31, 0x2e, 0x6d, 0x63, 0x63, 0x30, 0x30, 0x31, 0x2e,
0x33, 0x67, 0x70, 0x70, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x6f, 0x72, 0x67,
0x00, 0x60, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01, 0x00, 0x56, 0x40,
0x01, 0x32, 0x00, 0x50, 0x00, 0x08, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x08};
memcpy(sdu->msg, ng_setup_resp, sizeof(ng_setup_resp));
sdu->N_bytes = sizeof(ng_setup_resp);
TESTASSERT(ngap_obj.handle_amf_rx_msg(std::move(sdu), amf_addr, rcvinfo, flags));
}
int main(int argc, char** argv)
{
// Setup logging.
auto& logger = srslog::fetch_basic_logger("NGAP");
logger.set_level(srslog::basic_levels::debug);
logger.set_hex_dump_max_size(-1);
srsran::task_scheduler task_sched;
dummy_socket_manager rx_sockets;
ngap ngap_obj(&task_sched, logger, &rx_sockets);
const char* amf_addr_str = "127.0.0.1";
const uint32_t AMF_PORT = 38412;
amf_dummy amf(amf_addr_str, AMF_PORT);
ngap_args_t args = {};
args.cell_id = 0x01;
args.gnb_id = 0x19B;
args.mcc = 907;
args.mnc = 70;
args.ngc_bind_addr = "127.0.0.100";
args.tac = 7;
args.gtp_bind_addr = "127.0.0.100";
args.amf_addr = amf_addr_str;
args.gnb_name = "srsgnb01";
rrc_interface_ngap_nr rrc;
ngap_obj.init(args, &rrc);
// Start the log backend.
srsran::test_init(argc, argv);
run_ng_setup(ngap_obj, amf);
}

@ -482,6 +482,9 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
TESTASSERT(recfg_r8.meas_cfg.meas_gap_cfg.type().value == setup_opts::setup);
TESTASSERT((1 + recfg_r8.meas_cfg.meas_gap_cfg.setup().gap_offset.type().value) * 40u ==
tester.cfg.cell_list[1].meas_cfg.meas_gap_period);
auto* ue_cfg = &tester.mac.ue_db[tester.rnti];
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == srsenb::sched_interface::ue_bearer_cfg_t::DL);
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == srsenb::sched_interface::ue_bearer_cfg_t::DL);
/* Test Case: The UE sends a C-RNTI CE. Bearers are reestablished, PHY is configured */
tester.pdcp.last_sdu.sdu = nullptr;
@ -489,8 +492,14 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
TESTASSERT(tester.rlc.ue_db[tester.rnti].reest_sdu_counter == 0);
TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
TESTASSERT(tester.phy.phy_cfg_set);
TESTASSERT(tester.phy.last_cfg.size() == 1 and tester.mac.ue_db[tester.rnti].supported_cc_list.size() == 1);
TESTASSERT(tester.phy.last_cfg[0].enb_cc_idx == tester.mac.ue_db[tester.rnti].supported_cc_list[0].enb_cc_idx);
TESTASSERT(tester.phy.last_cfg.size() == 1 and ue_cfg->supported_cc_list.size() == 1);
TESTASSERT(tester.phy.last_cfg[0].enb_cc_idx == ue_cfg->supported_cc_list[0].enb_cc_idx);
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb0)].direction ==
srsenb::sched_interface::ue_bearer_cfg_t::BOTH);
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb1)].direction ==
srsenb::sched_interface::ue_bearer_cfg_t::BOTH);
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb2)].direction ==
srsenb::sched_interface::ue_bearer_cfg_t::BOTH);
/* Test Case: The UE receives a duplicate C-RNTI CE. Nothing should happen */
if (test_params == test_event::duplicate_crnti_ce) {
@ -506,13 +515,13 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
test_helpers::copy_msg_to_buffer(pdu, recfg_complete);
tester.rrc.write_pdu(tester.rnti, srb_to_lcid(lte_srb::srb2), std::move(pdu));
TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
sched_interface::ue_cfg_t& ue_cfg = tester.mac.ue_db[tester.rnti];
TESTASSERT(ue_cfg.pucch_cfg.sr_configured);
TESTASSERT(ue_cfg.pucch_cfg.n_pucch_sr == phy_cfg_ded.sched_request_cfg.setup().sr_pucch_res_idx);
TESTASSERT(ue_cfg.pucch_cfg.I_sr == phy_cfg_ded.sched_request_cfg.setup().sr_cfg_idx);
TESTASSERT(ue_cfg.supported_cc_list[0].dl_cfg.cqi_report.pmi_idx ==
ue_cfg = &tester.mac.ue_db[tester.rnti];
TESTASSERT(ue_cfg->pucch_cfg.sr_configured);
TESTASSERT(ue_cfg->pucch_cfg.n_pucch_sr == phy_cfg_ded.sched_request_cfg.setup().sr_pucch_res_idx);
TESTASSERT(ue_cfg->pucch_cfg.I_sr == phy_cfg_ded.sched_request_cfg.setup().sr_cfg_idx);
TESTASSERT(ue_cfg->supported_cc_list[0].dl_cfg.cqi_report.pmi_idx ==
phy_cfg_ded.cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx);
TESTASSERT(ue_cfg.pucch_cfg.n_pucch == phy_cfg_ded.cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx);
TESTASSERT(ue_cfg->pucch_cfg.n_pucch == phy_cfg_ded.cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx);
/* Test Case: The RRC should be able to start a new handover */
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x05, 0xBC, 0x80}; // PCI == 1

@ -184,14 +184,14 @@ public:
class mac_mobility_dummy : public mac_dummy
{
public:
int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override
int ue_cfg(uint16_t rnti, const sched_interface::ue_cfg_t* cfg) override
{
ue_db[rnti] = *cfg;
return 0;
}
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override
int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface::ue_cfg_t& cfg) override
{
ue_db[crnti] = *cfg;
ue_db[crnti] = cfg;
return 0;
}
std::map<uint16_t, sched_interface::ue_cfg_t> ue_db;

@ -43,7 +43,6 @@ link_directories(
# Add subdirectories
########################################################################
add_subdirectory(src)
add_subdirectory(test)
########################################################################
# Default configuration files

@ -177,6 +177,12 @@ public:
*/
uint32_t get_ul_earfcn(uint32_t dl_earfcn);
/**
* @brief Resets measurements from a given CC
* @param cc_idx CC index
*/
void reset_measurements(uint32_t cc_idx);
void update_measurements(uint32_t cc_idx,
const srsran_chest_dl_res_t& chest_res,
srsran_dl_sf_cfg_t sf_cfg_dl,
@ -227,32 +233,26 @@ public:
}
}
}
void reset_neighbour_cells()
{
for (uint32_t i = 0; i < SRSRAN_MAX_CARRIERS; i++) {
avg_rsrp_neigh[i] = NAN;
}
}
private:
std::mutex meas_mutex;
float pathloss[SRSRAN_MAX_CARRIERS] = {};
float cur_pathloss = 0.0f;
float cur_pusch_power = 0.0f;
float avg_rsrp[SRSRAN_MAX_CARRIERS] = {};
float avg_rsrp_dbm[SRSRAN_MAX_CARRIERS] = {};
float avg_rsrq_db[SRSRAN_MAX_CARRIERS] = {};
float avg_rssi_dbm[SRSRAN_MAX_CARRIERS] = {};
float avg_cfo_hz[SRSRAN_MAX_CARRIERS] = {};
float rx_gain_offset = 0.0f;
float avg_sinr_db[SRSRAN_MAX_CARRIERS] = {};
float avg_snr_db[SRSRAN_MAX_CARRIERS] = {};
float avg_noise[SRSRAN_MAX_CARRIERS] = {};
float avg_rsrp_neigh[SRSRAN_MAX_CARRIERS] = {};
uint32_t pcell_report_period = 0;
uint32_t rssi_read_cnt = 0;
float cur_pathloss = 0.0f;
float cur_pusch_power = 0.0f;
float rx_gain_offset = 0.0f;
std::array<float, SRSRAN_MAX_CARRIERS> pathloss = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rsrp = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rsrp_dbm = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rsrq_db = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rssi_dbm = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_cfo_hz = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_sinr_db = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_snr_db = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_noise = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rsrp_neigh = {};
static constexpr uint32_t pcell_report_period = 20;
uint32_t rssi_read_cnt = 0;
rsrp_insync_itf* insync_itf = nullptr;

@ -20,6 +20,7 @@
add_subdirectory(phy)
add_subdirectory(stack)
add_subdirectory(test)
# Link libstdc++ and libgcc
if(BUILD_STATIC)

@ -18,6 +18,8 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(test)
file(GLOB_RECURSE SOURCES "*.cc")
add_library(srsue_phy STATIC ${SOURCES})

@ -558,6 +558,11 @@ void cc_worker::decode_phich()
void cc_worker::update_measurements(std::vector<phy_meas_t>& serving_cells, cf_t* rssi_power_buffer)
{
// Do not update any measurement if the CC is not configured to prevent false or inaccurate data
if (not phy->cell_state.is_configured(cc_idx)) {
return;
}
phy->update_measurements(
cc_idx, ue_dl.chest_res, sf_cfg_dl, ue_dl_cfg.cfg.pdsch.rs_power, serving_cells, rssi_power_buffer);
}

@ -538,6 +538,10 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn)
}
}
// Reset measurements for the given CC after all workers finished processing and have been configured to ensure the
// measurements are not overwritten
common.reset_measurements(cc_idx);
// Change frequency only if the earfcn was modified
if (earfcn_is_different) {
double dl_freq = srsran_band_fd(earfcn) * 1e6;

@ -620,8 +620,31 @@ void phy_common::update_cfo_measurement(uint32_t cc_idx, float cfo_hz)
{
std::unique_lock<std::mutex> lock(meas_mutex);
// use SNR EMA coefficient for averaging
avg_cfo_hz[cc_idx] = SRSRAN_VEC_EMA(cfo_hz, avg_cfo_hz[cc_idx], args->snr_ema_coeff);
// Use SNR EMA coefficient for averaging
avg_cfo_hz[cc_idx] = SRSRAN_VEC_SAFE_EMA(cfo_hz, avg_cfo_hz[cc_idx], args->snr_ema_coeff);
}
void phy_common::reset_measurements(uint32_t cc_idx)
{
// If the CC index exceeds the maximum number of carriers, reset them all
if (cc_idx >= SRSRAN_MAX_CARRIERS) {
for (uint32_t cc = 0; cc < SRSRAN_MAX_CARRIERS; cc++) {
reset_measurements(cc);
}
}
// Default all metrics to NAN to prevent providing invalid information on traces and other layers
std::unique_lock<std::mutex> lock(meas_mutex);
pathloss[cc_idx] = NAN;
avg_rsrp[cc_idx] = NAN;
avg_rsrp_dbm[cc_idx] = NAN;
avg_rsrq_db[cc_idx] = NAN;
avg_rssi_dbm[cc_idx] = NAN;
avg_cfo_hz[cc_idx] = NAN;
avg_sinr_db[cc_idx] = NAN;
avg_snr_db[cc_idx] = NAN;
avg_noise[cc_idx] = NAN;
avg_rsrp_neigh[cc_idx] = NAN;
}
void phy_common::update_measurements(uint32_t cc_idx,
@ -653,7 +676,7 @@ void phy_common::update_measurements(uint32_t cc_idx,
30)
: 0;
if (std::isnormal(rssi_dbm)) {
avg_rssi_dbm[0] = SRSRAN_VEC_EMA(rssi_dbm, avg_rssi_dbm[0], args->snr_ema_coeff);
avg_rssi_dbm[0] = SRSRAN_VEC_SAFE_EMA(rssi_dbm, avg_rssi_dbm[0], args->snr_ema_coeff);
}
rx_gain_offset = get_radio()->get_rx_gain() + args->rx_gain_offset;
@ -667,21 +690,17 @@ void phy_common::update_measurements(uint32_t cc_idx,
// Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC
float rsrq_db = chest_res.rsrq_db;
if (std::isnormal(rsrq_db)) {
if (!(sf_cfg_dl.tti % pcell_report_period) || !std::isnormal(avg_rsrq_db[cc_idx])) {
avg_rsrq_db[cc_idx] = rsrq_db;
} else {
avg_rsrq_db[cc_idx] = SRSRAN_VEC_CMA(rsrq_db, avg_rsrq_db[cc_idx], sf_cfg_dl.tti % pcell_report_period);
// Reset average RSRQ measurement
if (sf_cfg_dl.tti % pcell_report_period == 0) {
avg_rsrq_db[cc_idx] = NAN;
}
avg_rsrq_db[cc_idx] = SRSRAN_VEC_SAFE_CMA(rsrq_db, avg_rsrq_db[cc_idx], sf_cfg_dl.tti % pcell_report_period);
}
// Average RSRP taken from CRS
float rsrp_lin = chest_res.rsrp;
if (std::isnormal(rsrp_lin)) {
if (!std::isnormal(avg_rsrp[cc_idx])) {
avg_rsrp[cc_idx] = rsrp_lin;
} else {
avg_rsrp[cc_idx] = SRSRAN_VEC_EMA(rsrp_lin, avg_rsrp[cc_idx], snr_ema_coeff);
}
avg_rsrp[cc_idx] = SRSRAN_VEC_SAFE_EMA(rsrp_lin, avg_rsrp[cc_idx], snr_ema_coeff);
}
/* Correct absolute power measurements by RX gain offset */
@ -689,11 +708,11 @@ void phy_common::update_measurements(uint32_t cc_idx,
// Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC
if (std::isnormal(rsrp_dbm)) {
if (!(sf_cfg_dl.tti % pcell_report_period) || !std::isnormal(avg_rsrp_dbm[cc_idx])) {
avg_rsrp_dbm[cc_idx] = rsrp_dbm;
} else {
avg_rsrp_dbm[cc_idx] = SRSRAN_VEC_CMA(rsrp_dbm, avg_rsrp_dbm[cc_idx], sf_cfg_dl.tti % pcell_report_period);
// Reset average RSRP measurement
if (sf_cfg_dl.tti % pcell_report_period == 0) {
avg_rsrp_dbm[cc_idx] = NAN;
}
avg_rsrp_dbm[cc_idx] = SRSRAN_VEC_SAFE_CMA(rsrp_dbm, avg_rsrp_dbm[cc_idx], sf_cfg_dl.tti % pcell_report_period);
}
// Compute PL
@ -702,11 +721,7 @@ void phy_common::update_measurements(uint32_t cc_idx,
// Average noise
float cur_noise = chest_res.noise_estimate;
if (std::isnormal(cur_noise)) {
if (!std::isnormal(avg_noise[cc_idx])) {
avg_noise[cc_idx] = cur_noise;
} else {
avg_noise[cc_idx] = SRSRAN_VEC_EMA(cur_noise, avg_noise[cc_idx], snr_ema_coeff);
}
avg_noise[cc_idx] = SRSRAN_VEC_SAFE_EMA(cur_noise, avg_noise[cc_idx], snr_ema_coeff);
}
// Calculate SINR using CRS from neighbours if are detected
@ -723,20 +738,12 @@ void phy_common::update_measurements(uint32_t cc_idx,
// Average sinr in the log domain
if (std::isnormal(sinr_db)) {
if (!std::isnormal(avg_sinr_db[cc_idx])) {
avg_sinr_db[cc_idx] = sinr_db;
} else {
avg_sinr_db[cc_idx] = SRSRAN_VEC_EMA(sinr_db, avg_sinr_db[cc_idx], snr_ema_coeff);
}
avg_sinr_db[cc_idx] = SRSRAN_VEC_SAFE_EMA(sinr_db, avg_sinr_db[cc_idx], snr_ema_coeff);
}
// Average snr in the log domain
if (std::isnormal(chest_res.snr_db)) {
if (!std::isnormal(avg_snr_db[cc_idx])) {
avg_snr_db[cc_idx] = chest_res.snr_db;
} else {
avg_snr_db[cc_idx] = SRSRAN_VEC_EMA(chest_res.snr_db, avg_snr_db[cc_idx], snr_ema_coeff);
}
avg_snr_db[cc_idx] = SRSRAN_VEC_SAFE_EMA(chest_res.snr_db, avg_snr_db[cc_idx], snr_ema_coeff);
}
// Store metrics
@ -751,9 +758,9 @@ void phy_common::update_measurements(uint32_t cc_idx,
set_ch_metrics(cc_idx, ch);
// Prepare measurements for serving cells
bool active = cell_state.is_configured(cc_idx);
if (active && ((sf_cfg_dl.tti % pcell_report_period) == pcell_report_period - 1)) {
// Prepare measurements for serving cells - skip if any measurement is invalid assuming pure zeros are not possible
if (std::isnormal(avg_rsrp_dbm[cc_idx]) and
std::isnormal(avg_cfo_hz[cc_idx] and ((sf_cfg_dl.tti % pcell_report_period) == pcell_report_period - 1))) {
phy_meas_t meas = {};
meas.rsrp = avg_rsrp_dbm[cc_idx];
meas.rsrq = avg_rsrq_db[cc_idx];
@ -875,25 +882,17 @@ void phy_common::reset()
{
reset_radio();
sr_enabled = false;
cur_pathloss = 0;
cur_pusch_power = 0;
sr_last_tx_tti = -1;
pcell_report_period = 20;
last_ri = 0;
sr_enabled = false;
cur_pathloss = 0;
cur_pusch_power = 0;
sr_last_tx_tti = -1;
last_ri = 0;
{
std::unique_lock<std::mutex> lock(meas_mutex);
ZERO_OBJECT(pathloss);
ZERO_OBJECT(avg_sinr_db);
ZERO_OBJECT(avg_snr_db);
ZERO_OBJECT(avg_rsrp);
ZERO_OBJECT(avg_rsrp_dbm);
ZERO_OBJECT(avg_rsrq_db);
}
cell_state.reset();
// Reset all measurements
reset_measurements(SRSRAN_MAX_CARRIERS);
reset_neighbour_cells();
// Reset all SCell states
cell_state.reset();
// Note: Using memset to reset these members is forbidden because they are real objects, not plain arrays.
{

@ -18,6 +18,8 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(test)
set(SOURCES demux.cc dl_harq.cc mac.cc mux.cc proc_bsr.cc proc_phr.cc proc_ra.cc proc_sr.cc ul_harq.cc)
add_library(srsue_mac STATIC ${SOURCES})
target_link_libraries(srsue_mac srsue_mac_common ${ATOMIC_LIBS})

@ -18,17 +18,6 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(phy)
add_subdirectory(upper)
if (ENABLE_TTCN3)
add_subdirectory(ttcn3)
endif (ENABLE_TTCN3)
add_executable(metrics_test metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc)
target_link_libraries(metrics_test srsran_phy srsran_common)
add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv)
add_executable(mac_test mac_test.cc)
target_link_libraries(mac_test srsue_mac srsue_phy srsran_common srsran_mac srsran_phy srsran_radio srsran_asn1 rrc_asn1 ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
add_test(mac_test mac_test)

@ -18,6 +18,8 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(test)
set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc phy_controller.cc)
add_library(srsue_rrc STATIC ${SOURCES})

@ -1751,16 +1751,20 @@ srsran::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc
return proc_outcome_t::yield; // wait for t304 expiry
}
// Have RRCReconfComplete message ready when Msg3 is sent
rrc_ptr->send_rrc_con_reconfig_complete();
// Note: We delay the enqueuing of RRC Reconf Complete message to avoid that the message goes in an UL grant
// directed at the old RNTI.
rrc_ptr->task_sched.defer_callback(4, [this]() {
// Have RRCReconfComplete message ready when Msg3 is sent
rrc_ptr->send_rrc_con_reconfig_complete();
// SCell addition/removal can take some time to compute. Enqueue in a background task and do it in the end.
rrc_ptr->apply_scell_config(&recfg_r8, false);
// SCell addition/removal can take some time to compute. Enqueue in a background task and do it in the end.
rrc_ptr->apply_scell_config(&recfg_r8, false);
// Send PDCP status report if configured
rrc_ptr->pdcp->send_status_report();
// Send PDCP status report if configured
rrc_ptr->pdcp->send_status_report();
Info("Finished HO configuration. Waiting PHY to synchronize with target cell");
Info("Finished HO configuration. Waiting PHY to synchronize with target cell");
});
return proc_outcome_t::yield;
}

@ -18,15 +18,6 @@
# and at http://www.gnu.org/licenses/.
#
add_executable(usim_test usim_test.cc)
target_link_libraries(usim_test srsue_upper srsran_upper srsran_phy rrc_asn1)
add_test(usim_test usim_test)
if(HAVE_PCSC)
add_executable(pcsc_usim_test pcsc_usim_test.cc)
target_link_libraries(pcsc_usim_test srsue_upper srsran_upper srsran_phy)
endif(HAVE_PCSC)
add_executable(rrc_reconfig_test rrc_reconfig_test.cc)
target_link_libraries(rrc_reconfig_test srsue_upper srsran_upper srsran_phy rrc_asn1)
add_test(rrc_reconfig_test rrc_reconfig_test)
@ -35,18 +26,6 @@ add_executable(rrc_meas_test rrc_meas_test.cc)
target_link_libraries(rrc_meas_test srsue_rrc srsue_upper srsran_upper srsran_phy rrc_asn1 rrc_nr_asn1)
add_test(rrc_meas_test rrc_meas_test)
add_executable(nas_test nas_test.cc)
target_link_libraries(nas_test srsue_upper srsran_upper srsran_phy rrc_asn1)
add_test(nas_test nas_test)
add_executable(gw_test gw_test.cc)
target_link_libraries(gw_test srsue_upper srsran_upper srsran_phy)
add_test(gw_test gw_test)
add_executable(tft_test tft_test.cc)
target_link_libraries(tft_test srsue_upper srsran_upper srsran_phy)
add_test(tft_test tft_test)
add_executable(rrc_phy_ctrl_test rrc_phy_ctrl_test.cc)
target_link_libraries(rrc_phy_ctrl_test srsran_common srsue_rrc ${ATOMIC_LIBS})
add_test(rrc_phy_ctrl_test rrc_phy_ctrl_test)
@ -66,5 +45,4 @@ if (NOT ${BUILD_CMD} STREQUAL "")
add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD})
else(NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "No post-build command defined")
endif (NOT ${BUILD_CMD} STREQUAL "")
endif (NOT ${BUILD_CMD} STREQUAL "")

@ -18,6 +18,8 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(test)
set(SOURCES nas.cc nas_emm_state.cc nas_idle_procedures.cc gw.cc usim_base.cc usim.cc tft_packet_filter.cc)
if(HAVE_PCSC)

@ -0,0 +1,39 @@
#
# 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.
#
add_executable(usim_test usim_test.cc)
target_link_libraries(usim_test srsue_upper srsran_upper srsran_phy rrc_asn1)
add_test(usim_test usim_test)
if(HAVE_PCSC)
add_executable(pcsc_usim_test pcsc_usim_test.cc)
target_link_libraries(pcsc_usim_test srsue_upper srsran_upper srsran_phy)
endif(HAVE_PCSC)
add_executable(nas_test nas_test.cc)
target_link_libraries(nas_test srsue_upper srsran_upper srsran_phy rrc_asn1)
add_test(nas_test nas_test)
add_executable(gw_test gw_test.cc)
target_link_libraries(gw_test srsue_upper srsran_upper srsran_phy)
add_test(gw_test gw_test)
add_executable(tft_test tft_test.cc)
target_link_libraries(tft_test srsue_upper srsran_upper srsran_phy)
add_test(tft_test tft_test)
########################################################################
# Option to run command after build (useful for remote builds)
########################################################################
if (NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "Added custom post-build command: ${BUILD_CMD}")
add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD})
else(NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "No post-build command defined")
endif (NOT ${BUILD_CMD} STREQUAL "")

@ -0,0 +1,15 @@
#
# 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.
#
if (ENABLE_TTCN3)
add_subdirectory(ttcn3)
endif (ENABLE_TTCN3)
add_executable(metrics_test metrics_test.cc ../metrics_stdout.cc ../metrics_csv.cc)
target_link_libraries(metrics_test srsran_phy srsran_common)
add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv)

@ -41,4 +41,4 @@ set(LINK_LIBRARIES srsue_stack
target_link_libraries(ttcn3_dut ${LINK_LIBRARIES})
include_directories(${PROJECT_SOURCE_DIR}/srsue/test/ttcn3/hdr)
include_directories(${PROJECT_SOURCE_DIR}/srsue/src/test/ttcn3/hdr)

@ -19,7 +19,7 @@
*
*/
#include "srsue/test/ttcn3/hdr/ttcn3_syssim.h"
#include "ttcn3_syssim.h"
#include "dut_utils.h"
#include "srsran/mac/pdu_queue.h"
#include "srsran/srslog/srslog.h"

@ -19,7 +19,7 @@
*
*/
#include "srsue/test/ttcn3/hdr/ttcn3_ue.h"
#include "ttcn3_ue.h"
#include "lte_ttcn3_phy.h"
#include "srsue/hdr/stack/ue_stack_lte.h"
#include <sstream>

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
include_directories(${PROJECT_SOURCE_DIR}/srsue/test/ttcn3/hdr)
include_directories(${PROJECT_SOURCE_DIR}/srsue/src/test/ttcn3/hdr)
add_executable(rapidjson_test rapidjson_test.cc)
target_link_libraries(rapidjson_test srsran_common)

@ -22,7 +22,6 @@
#include "srsran/common/test_common.h"
#include "ttcn3_helpers.h"
#include <iostream>
#include <srsue/test/ttcn3/hdr/ttcn3_helpers.h>
#include <stdio.h>
#include <vector>
Loading…
Cancel
Save