Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/interfaces/rrc_nr_interface_types.h
#	lib/include/srsran/phy/enb/enb_dl_nr.h
#	test/phy/nr_dl_flood.cc
master
Codebot 4 years ago committed by Your Name
commit 516951c41c

@ -521,8 +521,8 @@ endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Add colored output when using the Ninja generator # Add colored output when using the Ninja generator
if("Ninja" STREQUAL ${CMAKE_GENERATOR}) if("Ninja" STREQUAL ${CMAKE_GENERATOR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always") ADD_C_COMPILER_FLAG_IF_AVAILABLE("-fdiagnostics-color=always" HAVE_DIAGNOSTIC_COLOR_C)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-fdiagnostics-color=always" HAVE_DIAGNOSTIC_COLOR_CXX)
endif() endif()
# Add -Werror to C/C++ flags for newer compilers # Add -Werror to C/C++ flags for newer compilers

@ -236,11 +236,13 @@ public:
size_ = new_size; size_ = new_size;
return; return;
} }
T* old_data = data_; T* old_data = data_;
cap_ = new_size > new_cap ? new_size : new_cap; cap_ = new_size > new_cap ? new_size : new_cap;
if (cap_ > 0) { if (cap_ > 0) {
data_ = new T[cap_]; data_ = new T[cap_];
if (old_data != NULL) { if (old_data != NULL) {
srsran_assert(cap_ > size_, "Old size larger than new capacity in dyn_array\n");
std::copy(&old_data[0], &old_data[size_], data_); std::copy(&old_data[0], &old_data[size_], data_);
} }
} else { } else {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,87 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_NAS_5G_UTILS_H
#define SRSRAN_NAS_5G_UTILS_H
#include "srsran/asn1/asn1_utils.h"
#include "srsran/common/byte_buffer.h"
#include "srsran/config.h"
using namespace asn1;
namespace srsran {
namespace nas_5g {
struct ecies_scheme_profile_a_out {
uint8_t ecc_ephemeral_key[33];
std::vector<uint8_t> ciphertext;
uint8_t mac_tag[8];
};
struct ecies_scheme_profile_b_out {
uint8_t ecc_ephemeral_key[32];
std::vector<uint8_t> ciphertext;
uint8_t mac_tag[8];
};
template <typename Enum, int bl>
SRSASN_CODE unpack_enum(asn1::cbit_ref& bref, Enum* e)
{
uint32_t tmp = {};
HANDLE_CODE(bref.unpack(tmp, bl));
*e = static_cast<Enum>(tmp);
return SRSASN_SUCCESS;
}
template <typename Enum, int bl>
SRSASN_CODE pack_enum(asn1::bit_ref& bref, Enum e)
{
uint32_t tmp = static_cast<uint32_t>(e);
HANDLE_CODE(bref.pack(tmp, bl));
return SRSASN_SUCCESS;
}
template <class EnumType, uint32_t bit_length_>
class nas_enumerated : public EnumType
{
public:
static const uint32_t bit_length = bit_length_;
nas_enumerated() {}
nas_enumerated(typename EnumType::options o) { EnumType::value = o; }
SRSASN_CODE pack(asn1::bit_ref& bref) const
{
uint32_t tmp = static_cast<uint32_t>(EnumType::value);
HANDLE_CODE(bref.pack(tmp, bit_length));
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(asn1::cbit_ref& bref)
{
uint32_t tmp = {};
HANDLE_CODE(bref.unpack(tmp, bit_length));
*this = static_cast<typename EnumType::options>(tmp);
return SRSASN_SUCCESS;
}
EnumType& operator=(EnumType v)
{
EnumType::value = v;
return *this;
}
operator typename EnumType::options() const { return EnumType::value; }
};
SRSASN_CODE unpack_mcc_mnc(uint8_t* mcc_bytes, uint8_t* mnc_bytes, asn1::cbit_ref& bref);
SRSASN_CODE pack_mcc_mnc(uint8_t* mcc_bytes, uint8_t* mnc_bytes, asn1::bit_ref& bref);
} // namespace nas_5g
} // namespace srsran
#endif // MANUAL_H

@ -2263,11 +2263,8 @@ struct setup_release_c {
// choice methods // choice methods
setup_release_c() = default; setup_release_c() = default;
void set(typename types::options e = types::nulltype);
types type() const { return type_; } types type() const { return type_; }
SRSASN_CODE pack(bit_ref& bref) const;
SRSASN_CODE unpack(cbit_ref& bref);
void to_json(json_writer& j) const;
// getters // getters
elem_type_paramT_& setup() elem_type_paramT_& setup()
{ {
@ -2280,6 +2277,57 @@ struct setup_release_c {
return c; return c;
} }
void set_release() { set(types::release); } void set_release() { set(types::release); }
void set(typename types::options e) { type_ = e; }
void to_json(json_writer& j) const
{
j.start_obj();
switch (type_) {
case types::release:
break;
case types::setup:
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
}
j.end_obj();
}
SRSASN_CODE pack(bit_ref& bref) const
{
type_.pack(bref);
switch (type_) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.pack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
SRSASN_CODE unpack(cbit_ref& bref)
{
types e;
e.unpack(bref);
set(e);
switch (type_) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.unpack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_DECODE_FAIL;
}
return SRSASN_SUCCESS;
}
elem_type_paramT_& set_setup() elem_type_paramT_& set_setup()
{ {
set(types::setup); set(types::setup);

@ -22,10 +22,10 @@
#ifndef SRSRAN_RRC_NR_UTILS_H #ifndef SRSRAN_RRC_NR_UTILS_H
#define SRSRAN_RRC_NR_UTILS_H #define SRSRAN_RRC_NR_UTILS_H
#include "srsran/common/phy_cfg_nr.h"
#include "srsran/interfaces/mac_interface_types.h" #include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/pdcp_interface_types.h" #include "srsran/interfaces/pdcp_interface_types.h"
#include "srsran/interfaces/rlc_interface_types.h" #include "srsran/interfaces/rlc_interface_types.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include "srsran/interfaces/sched_interface.h" #include "srsran/interfaces/sched_interface.h"
/************************ /************************
@ -84,7 +84,7 @@ bool make_phy_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type, srsran_
bool make_phy_tdd_cfg(const asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common, bool make_phy_tdd_cfg(const asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common,
srsran_tdd_config_nr_t* srsran_tdd_config_nr); srsran_tdd_config_nr_t* srsran_tdd_config_nr);
bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg, bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg,
srsran_ue_dl_nr_harq_ack_cfg_t* srsran_ue_dl_nr_harq_ack_cfg); srsran_harq_ack_cfg_hl_t* srsran_ue_dl_nr_harq_ack_cfg);
bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset); bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset);
bool make_phy_search_space_cfg(const asn1::rrc_nr::search_space_s& search_space, bool make_phy_search_space_cfg(const asn1::rrc_nr::search_space_s& search_space,
srsran_search_space_t* srsran_search_space); srsran_search_space_t* srsran_search_space);

@ -130,7 +130,14 @@ public:
const myobj& front() const { return q.front(); } const myobj& front() const { return q.front(); }
size_t size() { return q.size(); } size_t size()
{
size_t len = 0;
pthread_mutex_lock(&mutex);
len = q.size();
pthread_mutex_unlock(&mutex);
return len;
}
private: private:
bool pop_(myobj* value, bool block) bool pop_(myobj* value, bool block)

@ -44,6 +44,7 @@ bool config_exists(std::string& filename, std::string default_name)
homedir = "."; homedir = ".";
} }
snprintf(full_path, sizeof(full_path), "%s/.config/srsran/%s", homedir, default_name.c_str()); snprintf(full_path, sizeof(full_path), "%s/.config/srsran/%s", homedir, default_name.c_str());
printf("Couldn't open %s, trying %s\n", filename.c_str(), full_path);
filename = std::string(full_path); filename = std::string(full_path);
// try to open again // try to open again
@ -52,6 +53,7 @@ bool config_exists(std::string& filename, std::string default_name)
// Last chance, try to find file in /etc/srsran // Last chance, try to find file in /etc/srsran
ZERO_OBJECT(full_path); ZERO_OBJECT(full_path);
snprintf(full_path, sizeof(full_path), "/etc/srsran/%s", default_name.c_str()); snprintf(full_path, sizeof(full_path), "/etc/srsran/%s", default_name.c_str());
printf("Couldn't open %s either, trying %s\n", filename.c_str(), full_path);
filename = std::string(full_path); filename = std::string(full_path);
// try to open again // try to open again

@ -163,7 +163,7 @@ private:
// state // state
std::mutex socket_mutex; std::mutex socket_mutex;
std::map<int, recv_callback_t> active_sockets; std::map<int, recv_callback_t> active_sockets;
bool running = false; std::atomic<bool> running = {false};
int pipefd[2] = {-1, -1}; int pipefd[2] = {-1, -1};
std::vector<int> rem_fd_tmp_list; std::vector<int> rem_fd_tmp_list;
std::condition_variable rem_cvar; std::condition_variable rem_cvar;

@ -0,0 +1,154 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_PHY_CFG_NR_H
#define SRSRAN_PHY_CFG_NR_H
#include "srsran/config.h"
#include "srsran/srsran.h"
#include <array>
#include <srsran/adt/bounded_vector.h>
#include <string>
namespace srsran {
/***************************
* PHY Config
**************************/
struct phy_cfg_nr_t {
/**
* SSB configuration
*/
struct ssb_cfg_t {
uint32_t periodicity_ms = 0;
std::array<bool, SRSRAN_SSB_NOF_CANDIDATES> position_in_burst = {};
srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_30kHz;
};
srsran_tdd_config_nr_t tdd = {};
srsran_sch_hl_cfg_nr_t pdsch = {};
srsran_sch_hl_cfg_nr_t pusch = {};
srsran_pucch_nr_hl_cfg_t pucch = {};
srsran_prach_cfg_t prach = {};
srsran_pdcch_cfg_nr_t pdcch = {};
srsran_harq_ack_cfg_hl_t harq_ack = {};
srsran_csi_hl_cfg_t csi = {};
srsran_carrier_nr_t carrier = {};
ssb_cfg_t ssb;
phy_cfg_nr_t() {}
/**
* @brief Computes the DCI configuration for the current UE configuration
*/
srsran_dci_cfg_nr_t get_dci_cfg() const;
/**
* @brief Asserts that the PDCCH configuration is valid for a given Search Space identifier
* @param ss_id Identifier
* @return true if the configuration is valid, false otherwise
*/
bool assert_ss_id(uint32_t ss_id) const;
/**
* @brief Calculates the DCI location candidates for a given search space and aggregation level
* @param slot_idx Slot index
* @param rnti UE temporal identifier
* @param ss_id Search Space identifier
* @param L Aggregation level
* @param[out] locations DCI candidate locations
* @return true if the configuration is valid, false otherwise
*/
bool get_dci_locations(
const uint32_t& slot_idx,
const uint16_t& rnti,
const uint32_t& ss_id,
const uint32_t& L,
srsran::bounded_vector<srsran_dci_location_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>& locations) const;
/**
* @brief Selects a valid DCI format for scheduling PDSCH and given Search Space identifier
* @param ss_id Identifier
* @return A valid DCI format if available, SRSRAN_DCI_FORMAT_NR_COUNT otherwise
*/
srsran_dci_format_nr_t get_dci_format_pdsch(uint32_t ss_id) const;
/**
* @brief Selects a valid DCI format for scheduling PUSCH and given Search Space identifier
* @param ss_id Identifier
* @return A valid DCI format if available, SRSRAN_DCI_FORMAT_NR_COUNT otherwise
*/
srsran_dci_format_nr_t get_dci_format_pusch(uint32_t ss_id) const;
/**
* @brief Fills PDSCH DCI context for C-RNTI using a search space identifier, DCI candidate location and RNTI
*/
bool get_dci_ctx_pdsch_rnti_c(uint32_t ss_id,
const srsran_dci_location_t& location,
const uint16_t& rnti,
srsran_dci_ctx_t& ctx) const;
/**
* @brief Fills PUSCH DCI context for C-RNTI using a search space identifier, DCI candidate location and RNTI
*/
bool get_dci_ctx_pusch_rnti_c(uint32_t ss_id,
const srsran_dci_location_t& location,
const uint16_t& rnti,
srsran_dci_ctx_t& ctx) const;
/**
* @brief Get PDSCH configuration for a given slot and DCI
*/
bool
get_pdsch_cfg(const srsran_slot_cfg_t& slot_cfg, const srsran_dci_dl_nr_t& dci, srsran_sch_cfg_nr_t& pdsch_cfg) const;
/**
* @brief Get PUSCH configuration for a given slot and DCI
*/
bool
get_pusch_cfg(const srsran_slot_cfg_t& slot_cfg, const srsran_dci_ul_nr_t& dci, srsran_sch_cfg_nr_t& pdsch_cfg) const;
/**
* @brief Get PDSCH ACK resource for a given PDSCH transmission
*/
bool get_pdsch_ack_resource(const srsran_dci_dl_nr_t& dci_dl, srsran_harq_ack_resource_t& ack_resource) const;
/**
* @brief Compute UCI configuration for the given slot from the pending PDSCH ACK resources, periodic CSI,
* periodic SR resources and so on.
*/
bool get_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_pdsch_ack_nr_t& pdsch_ack,
srsran_uci_cfg_nr_t& uci_cfg) const;
/**
* @brief Compute UCI configuration for PUCCH for the given slot from the pending PDSCH ACK resources, periodic CSI,
* periodic SR resources and so on.
*/
bool get_pucch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_uci_cfg_nr_t& uci_cfg,
srsran_pucch_nr_common_cfg_t& cfg,
srsran_pucch_nr_resource_t& resource) const;
/**
* @brief Compute UCI configuration for PUSCH for the given slot from the pending PDSCH ACK resources, periodic CSI,
* periodic SR resources and so on.
*/
bool get_pusch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_uci_cfg_nr_t& uci_cfg,
srsran_sch_cfg_nr_t& pusch_cfg) const;
};
} // namespace srsran
#endif // SRSRAN_PHY_CFG_NR_H

@ -0,0 +1,151 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_PHY_CFG_NR_DEFAULT_H
#define SRSRAN_PHY_CFG_NR_DEFAULT_H
#include "phy_cfg_nr.h"
namespace srsran {
class phy_cfg_nr_default_t : public phy_cfg_nr_t
{
public:
struct reference_cfg_t {
enum {
/**
* @brief Carrier reference configuration for 10MHz serving cell bandwidth
* - BW: 10 MHZ (52 PRB)
* - PCI: 500
* - SCS: 15 kHz
* - SSB: 5ms
*/
R_CARRIER_CUSTOM_10MHZ = 0,
} carrier = R_CARRIER_CUSTOM_10MHZ;
enum {
/**
* @brief TDD custom reference 5 slot DL and 5 slot UL
*/
R_TDD_CUSTOM_6_4 = 0,
} tdd = R_TDD_CUSTOM_6_4;
enum {
/**
* @brief Carrier reference configuration for 10MHz serving cell bandwidth
* - CORESET: all channel, 1 symbol
* - Single common Search Space
* - 2 possible candidate per aggregation level to allow DL and UL grants simultaneously
*/
R_PDCCH_CUSTOM_COMMON_SS = 0,
} pdcch = R_PDCCH_CUSTOM_COMMON_SS;
enum {
/**
* @brief Custom fallback baseline configuration, designed for component testing
* - Defined single common PDSCH time allocation starting at symbol index 1 and length 13
* - No DMRS dedicated configuration
*/
R_PDSCH_DEFAULT = 0,
} pdsch = R_PDSCH_DEFAULT;
enum {
/**
* @brief Custom fallback baseline configuration, designed for component testing
* - Single Time resource allocation
* - transmission starts at symbol index 0 for 14 symbols
* - k is 4 slots
* - No DMRS dedicated configuration
*/
R_PUSCH_DEFAULT = 0,
} pusch = R_PUSCH_DEFAULT;
enum {
/**
* @brief Custom single PUCCH resource per set
* - Format 1 for 1 or 2 bits
* - Format 2 for more than 2 bits
*/
R_PUCCH_CUSTOM_ONE = 0,
} pucch = R_PUCCH_CUSTOM_ONE;
enum {
/**
* @brief Sets the delay between PDSCH and HARQ feedback timing automatically
* - Dynamic HARQ ACK codebook
* - Guarantees a minimum delay of 4ms
* - Assume 15kHz SCS
* - Assume TDD pattern2 is not enabled
*/
R_HARQ_AUTO = 0,
} harq = R_HARQ_AUTO;
enum {
/**
* @brief Sets the PRACH configuration to an LTE compatible configuration
* - Configuration index 0
* - Frequency offset 2 PRB
* - Root sequence 2
*/
R_PRACH_DEFAULT_LTE,
} prach = R_PRACH_DEFAULT_LTE;
};
phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg);
private:
/**
* Carrier make helper methods
*/
static void make_carrier_custom_10MHz(srsran_carrier_nr_t& carrier);
/**
* TDD make helper methods
*/
static void make_tdd_custom_6_4(srsran_tdd_config_nr_t& tdd);
/**
* PDCCH make helper methods
*/
static void make_pdcch_custom_common_ss(srsran_pdcch_cfg_nr_t& pdcch, const srsran_carrier_nr_t& carrier);
/**
* PDSCH make helper methods
*/
static void make_pdsch_default(srsran_sch_hl_cfg_nr_t& pdsch);
/**
* PUSCH make helper methods
*/
static void make_pusch_default(srsran_sch_hl_cfg_nr_t& pusch);
/**
* PUCCH make helper methods
*/
static void make_pucch_custom_one(srsran_pucch_nr_hl_cfg_t& pucch);
/**
* HARQ make helper methods
*/
static void make_harq_auto(srsran_harq_ack_cfg_hl_t& harq,
const srsran_carrier_nr_t& carrier,
const srsran_tdd_config_nr_t& tdd_cfg);
/**
* PRACH make helper methods
*/
static void make_prach_default_lte(srsran_prach_cfg_t& prach);
};
} // namespace srsran
#endif // SRSRAN_PHY_CFG_NR_DEFAULT_H

@ -22,6 +22,7 @@
#ifndef SRSRAN_TASK_SCHEDULER_H #ifndef SRSRAN_TASK_SCHEDULER_H
#define SRSRAN_TASK_SCHEDULER_H #define SRSRAN_TASK_SCHEDULER_H
#include "block_queue.h"
#include "interfaces_common.h" #include "interfaces_common.h"
#include "multiqueue.h" #include "multiqueue.h"
#include "thread_pool.h" #include "thread_pool.h"
@ -33,7 +34,7 @@ class task_scheduler
{ {
public: public:
explicit task_scheduler(uint32_t default_extern_tasks_size = 512, uint32_t nof_timers_prealloc = 100) : explicit task_scheduler(uint32_t default_extern_tasks_size = 512, uint32_t nof_timers_prealloc = 100) :
external_tasks{default_extern_tasks_size}, timers{nof_timers_prealloc} external_tasks{default_extern_tasks_size}, timers{nof_timers_prealloc}, internal_tasks(512)
{ {
background_queue = external_tasks.add_queue(); background_queue = external_tasks.add_queue();
} }
@ -58,7 +59,12 @@ public:
} }
//! Enqueues internal task to be run in next tic //! Enqueues internal task to be run in next tic
void defer_task(srsran::move_task_t func) { internal_tasks.push_back(std::move(func)); } void defer_task(srsran::move_task_t func)
{
if (not internal_tasks.try_push(std::move(func))) {
srslog::fetch_basic_logger("COMN", false).warning("Couldn't add new internal task");
}
}
//! Defer the handling of the result of a background task to next tic //! Defer the handling of the result of a background task to next tic
void notify_background_task_result(srsran::move_task_t task) void notify_background_task_result(srsran::move_task_t task)
@ -99,21 +105,20 @@ public:
srsran::timer_handler* get_timer_handler() { return &timers; } srsran::timer_handler* get_timer_handler() { return &timers; }
private: private:
// Perform pending stack deferred tasks
void run_all_internal_tasks() void run_all_internal_tasks()
{ {
// Perform pending stack deferred tasks srsran::move_task_t task{};
// Note: Using a deque because tasks can enqueue new tasks, which would lead to while (internal_tasks.try_pop(task)) {
// reference invalidation in case of vector task();
while (not internal_tasks.empty()) {
internal_tasks.front()();
internal_tasks.pop_front();
} }
} }
srsran::task_multiqueue external_tasks; srsran::task_multiqueue external_tasks;
srsran::task_queue_handle background_queue; ///< Queue for handling the outcomes of tasks run in the background srsran::task_queue_handle background_queue; ///< Queue for handling the outcomes of tasks run in the background
srsran::timer_handler timers; srsran::timer_handler timers;
std::deque<srsran::move_task_t> internal_tasks; ///< enqueues stack tasks from within main thread. Avoids locking srsran::dyn_blocking_queue<srsran::move_task_t>
internal_tasks; ///< enqueues stack tasks from within main thread. Avoids locking
}; };
//! Task scheduler handle given to classes/functions running within the main control thread //! Task scheduler handle given to classes/functions running within the main control thread

@ -26,6 +26,7 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "srsran/common/buffer_pool.h"
#include "srsran/common/crash_handler.h" #include "srsran/common/crash_handler.h"
#include "srsran/common/srsran_assert.h" #include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h" #include "srsran/common/standard_streams.h"
@ -150,6 +151,13 @@ inline void test_init(int argc, char** argv)
srslog::init(); srslog::init();
} }
inline void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg)
{
pdu = srsran::make_byte_buffer();
memcpy(pdu->msg, msg.data(), msg.size());
pdu->N_bytes = msg.size();
}
} // namespace srsran } // namespace srsran
#define CONDERROR(cond, fmt, ...) srsran_assert(not(cond), fmt, ##__VA_ARGS__) #define CONDERROR(cond, fmt, ...) srsran_assert(not(cond), fmt, ##__VA_ARGS__)

@ -129,6 +129,30 @@ public:
virtual void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) = 0; virtual void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) = 0;
}; };
// RRC interfaces for NSA operation
/// X2AP inspired interface to allow EUTRA RRC to call NR RRC
class rrc_nr_interface_rrc
{
public:
/// Request addition of NR carrier for UE (TODO: add configuration check, QCI, security, etc.)
virtual int sgnb_addition_request(uint16_t rnti) = 0;
/// Provide information whether the requested configuration was applied successfully by the UE
virtual int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response) = 0;
};
/// X2AP inspired interface for response from NR RRC to EUTRA RRC
class rrc_eutra_interface_rrc_nr
{
public:
/// Signal successful addition of UE
virtual void sgnb_addition_ack(uint16_t rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) = 0;
virtual void sgnb_addition_reject(uint16_t rnti) = 0;
};
} // namespace srsenb } // namespace srsenb
#endif // SRSRAN_ENB_RRC_INTERFACES_H #endif // SRSRAN_ENB_RRC_INTERFACES_H

@ -251,14 +251,15 @@ public:
}; };
struct pusch_t { struct pusch_t {
srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration uint32_t pid = 0; ///< HARQ process ID
std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration
std::array<srsran_softbuffer_tx_t*, SRSRAN_MAX_TB> softbuffer_tx = {}; ///< Tx Softbuffer std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer
}; };
struct pucch_t { struct pucch_t {
srsran_uci_cfg_nr_t uci_cfg; srsran_uci_cfg_nr_t uci_cfg; ///< UCI configuration
srsran_pucch_nr_resource_t resource; srsran_pucch_nr_common_cfg_t pucch_cfg; ///< UE dedicated PUCCH configuration
srsran_pucch_nr_resource_t resource; ///< PUCCH resource
}; };
struct ul_sched_t { struct ul_sched_t {
@ -266,9 +267,24 @@ public:
srsran::bounded_vector<pucch_t, MAX_GRANTS> pucch; srsran::bounded_vector<pucch_t, MAX_GRANTS> pucch;
}; };
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0; struct pucch_info_t {
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0; srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0; // ... add signal measurements here
};
struct pusch_info_t {
uint16_t rnti;
uint32_t pid = 0; ///< HARQ process ID
srsran_pusch_res_nr_t pusch_data;
srsran_uci_cfg_nr_t uci_cfg; ///< Provides UCI configuration, so stack does not need to keep the pending state
// ... add signal measurements here
};
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0;
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0;
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0;
virtual int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) = 0;
virtual int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) = 0;
}; };
class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr

@ -1,147 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSRAN_RRC_NR_INTERFACE_TYPES_H
#define SRSRAN_RRC_NR_INTERFACE_TYPES_H
#include "srsran/config.h"
#include "srsran/srsran.h"
#include <array>
#include <string>
namespace srsran {
/***************************
* PHY Config
**************************/
struct phy_cfg_nr_t {
/**
* SSB configuration
*/
struct ssb_cfg_t {
uint32_t periodicity_ms = 0;
std::array<bool, SRSRAN_SSB_NOF_CANDIDATES> position_in_burst = {};
srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_30kHz;
};
srsran_tdd_config_nr_t tdd = {};
srsran_sch_hl_cfg_nr_t pdsch = {};
srsran_sch_hl_cfg_nr_t pusch = {};
srsran_pucch_nr_hl_cfg_t pucch = {};
srsran_prach_cfg_t prach = {};
srsran_pdcch_cfg_nr_t pdcch = {};
srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {};
srsran_csi_hl_cfg_t csi = {};
srsran_carrier_nr_t carrier = {};
ssb_cfg_t ssb;
phy_cfg_nr_t() {}
/**
* @param carrier
*/
srsran_dci_cfg_nr_t get_dci_cfg() const
{
srsran_dci_cfg_nr_t dci_cfg = {};
// Assume BWP bandwidth equals full channel bandwidth
dci_cfg.coreset0_bw = pdcch.coreset_present[0] ? srsran_coreset_get_bw(&pdcch.coreset[0]) : 0;
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_dl_active_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_active_bw = carrier.nof_prb;
// Iterate over all SS to select monitoring options
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; i++) {
// Skip not configured SS
if (not pdcch.search_space_present[i]) {
continue;
}
// Iterate all configured formats
for (uint32_t j = 0; j < pdcch.search_space[i].nof_formats; j++) {
if (pdcch.search_space[i].type == srsran_search_space_type_common_3 &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) {
dci_cfg.monitor_common_0_0 = true;
} else if (pdcch.search_space[i].type == srsran_search_space_type_ue &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) {
dci_cfg.monitor_0_0_and_1_0 = true;
} else if (pdcch.search_space[i].type == srsran_search_space_type_ue &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_1) {
dci_cfg.monitor_0_1_and_1_1 = true;
}
}
}
// Set PUSCH parameters
dci_cfg.enable_sul = false;
dci_cfg.enable_hopping = false;
// Set Format 0_1 and 1_1 parameters
dci_cfg.carrier_indicator_size = 0;
dci_cfg.harq_ack_codebok = harq_ack.harq_ack_codebook;
dci_cfg.nof_rb_groups = 0;
// Format 0_1 specific configuration (for PUSCH only)
dci_cfg.nof_ul_bwp = 0;
dci_cfg.nof_ul_time_res = (pusch.nof_dedicated_time_ra > 0)
? pusch.nof_dedicated_time_ra
: (pusch.nof_common_time_ra > 0) ? pusch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA;
dci_cfg.nof_srs = 1;
dci_cfg.nof_ul_layers = 1;
dci_cfg.pusch_nof_cbg = 0;
dci_cfg.report_trigger_size = 0;
dci_cfg.enable_transform_precoding = false;
dci_cfg.dynamic_dual_harq_ack_codebook = false;
dci_cfg.pusch_tx_config_non_codebook = false;
dci_cfg.pusch_ptrs = false;
dci_cfg.pusch_dynamic_betas = false;
dci_cfg.pusch_alloc_type = pusch.alloc;
dci_cfg.pusch_dmrs_type = pusch.dmrs_type;
dci_cfg.pusch_dmrs_max_len = pusch.dmrs_max_length;
// Format 1_1 specific configuration (for PDSCH only)
dci_cfg.nof_dl_bwp = 0;
dci_cfg.nof_dl_time_res = (pdsch.nof_dedicated_time_ra > 0)
? pdsch.nof_dedicated_time_ra
: (pdsch.nof_common_time_ra > 0) ? pdsch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA;
dci_cfg.nof_aperiodic_zp = 0;
dci_cfg.pdsch_nof_cbg = 0;
dci_cfg.nof_dl_to_ul_ack = harq_ack.nof_dl_data_to_ul_ack;
dci_cfg.pdsch_inter_prb_to_prb = false;
dci_cfg.pdsch_rm_pattern1 = false;
dci_cfg.pdsch_rm_pattern2 = false;
dci_cfg.pdsch_2cw = false;
dci_cfg.multiple_scell = false;
dci_cfg.pdsch_tci = false;
dci_cfg.pdsch_cbg_flush = false;
dci_cfg.pdsch_dynamic_bundling = false;
dci_cfg.pdsch_alloc_type = pdsch.alloc;
dci_cfg.pdsch_dmrs_type = pdsch.dmrs_type;
dci_cfg.pdsch_dmrs_max_len = pdsch.dmrs_max_length;
return dci_cfg;
};
};
} // namespace srsran
#endif // SRSRAN_RRC_NR_INTERFACE_TYPES_H

@ -109,21 +109,7 @@ public:
virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0; virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0;
}; };
class mac_interface_rrc_common class mac_interface_rrc
{
public:
// Class to handle UE specific RNTIs between RRC and MAC
typedef struct {
uint16_t crnti;
uint16_t rar_rnti;
uint16_t temp_rnti;
uint16_t tpc_rnti;
uint16_t sps_rnti;
uint64_t contention_id;
} ue_rnti_t;
};
class mac_interface_rrc : public mac_interface_rrc_common
{ {
public: public:
/* Instructs the MAC to start receiving BCCH */ /* Instructs the MAC to start receiving BCCH */
@ -147,9 +133,9 @@ public:
virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0; virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0;
virtual void get_rntis(ue_rnti_t* rntis) = 0; virtual uint16_t get_crnti() = 0;
virtual void set_contention_id(uint64_t uecri) = 0; virtual void set_contention_id(uint64_t uecri) = 0;
virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0;
virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0; virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0;
virtual void reset() = 0; virtual void reset() = 0;

@ -23,8 +23,8 @@
#define SRSRAN_UE_NR_INTERFACES_H #define SRSRAN_UE_NR_INTERFACES_H
#include "srsran/common/interfaces_common.h" #include "srsran/common/interfaces_common.h"
#include "srsran/common/phy_cfg_nr.h"
#include "srsran/interfaces/mac_interface_types.h" #include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include <array> #include <array>
#include <set> #include <set>
#include <string> #include <string>

@ -58,7 +58,6 @@ SRSRAN_API int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t*
/** /**
* @brief Estimates NR-PUCCH format 1 resource elements from their DMRS in the provided resource grid * @brief Estimates NR-PUCCH format 1 resource elements from their DMRS in the provided resource grid
* @param[in] q NR-PUCCH encoder/decoder object * @param[in] q NR-PUCCH encoder/decoder object
* @param[in] carrier Carrier configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 1 resource * @param[in] resource PUCCH format 1 resource
@ -67,7 +66,6 @@ SRSRAN_API int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t*
* @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise
*/ */
SRSRAN_API int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, SRSRAN_API int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
const srsran_carrier_nr_t* carrier,
const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_slot_cfg_t* slot, const srsran_slot_cfg_t* slot,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,
@ -94,7 +92,6 @@ int srsran_dmrs_pucch_format2_put(const srsran_pucch_nr_t* q,
/** /**
* @brief Estimates NR-PUCCH format 2 resource elements from their DMRS in the provided resource grid * @brief Estimates NR-PUCCH format 2 resource elements from their DMRS in the provided resource grid
* @param[in] q NR-PUCCH encoder/decoder object * @param[in] q NR-PUCCH encoder/decoder object
* @param[in] carrier Carrier configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 2 resource * @param[in] resource PUCCH format 2 resource
@ -103,7 +100,6 @@ int srsran_dmrs_pucch_format2_put(const srsran_pucch_nr_t* q,
* @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise
*/ */
int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q, int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
const srsran_carrier_nr_t* carrier,
const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_slot_cfg_t* slot, const srsran_slot_cfg_t* slot,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,

@ -1,91 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSRAN_ENB_DL_NR_H
#define SRSRAN_ENB_DL_NR_H
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/dft/ofdm.h"
#include "srsran/phy/phch/pdcch_cfg_nr.h"
#include "srsran/phy/phch/pdcch_nr.h"
#include "srsran/phy/phch/pdsch_nr.h"
typedef struct SRSRAN_API {
srsran_pdsch_nr_args_t pdsch;
srsran_pdcch_nr_args_t pdcch;
uint32_t nof_tx_antennas;
uint32_t nof_max_prb;
} srsran_enb_dl_nr_args_t;
typedef struct SRSRAN_API {
uint32_t max_prb;
uint32_t nof_tx_antennas;
srsran_carrier_nr_t carrier;
srsran_pdcch_cfg_nr_t pdcch_cfg;
srsran_ofdm_t fft[SRSRAN_MAX_PORTS];
cf_t* sf_symbols[SRSRAN_MAX_PORTS];
srsran_pdsch_nr_t pdsch;
srsran_dmrs_sch_t dmrs;
srsran_dci_nr_t dci; ///< Stores DCI configuration
srsran_pdcch_nr_t pdcch;
} srsran_enb_dl_nr_t;
SRSRAN_API int
srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS], const srsran_enb_dl_nr_args_t* args);
SRSRAN_API int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_t* carrier);
SRSRAN_API int srsran_enb_dl_nr_set_pdcch_config(srsran_enb_dl_nr_t* q,
const srsran_pdcch_cfg_nr_t* cfg,
const srsran_dci_cfg_nr_t* dci_cfg);
SRSRAN_API void srsran_enb_dl_nr_free(srsran_enb_dl_nr_t* q);
SRSRAN_API int srsran_enb_dl_nr_base_zero(srsran_enb_dl_nr_t* q);
SRSRAN_API void srsran_enb_dl_nr_gen_signal(srsran_enb_dl_nr_t* q);
SRSRAN_API int srsran_enb_dl_nr_pdcch_put_dl(srsran_enb_dl_nr_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_dci_dl_nr_t* dci_dl);
SRSRAN_API int srsran_enb_dl_nr_pdcch_put_ul(srsran_enb_dl_nr_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_dci_ul_nr_t* dci_ul);
SRSRAN_API int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q,
const srsran_slot_cfg_t* slot,
const srsran_sch_cfg_nr_t* cfg,
uint8_t* data[SRSRAN_MAX_TB]);
SRSRAN_API int
srsran_enb_dl_nr_pdsch_info(const srsran_enb_dl_nr_t* q, const srsran_sch_cfg_nr_t* cfg, char* str, uint32_t str_len);
SRSRAN_API int
srsran_enb_dl_nr_pdcch_dl_info(const srsran_enb_dl_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
SRSRAN_API int
srsran_enb_dl_nr_pdcch_ul_info(const srsran_enb_dl_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len);
#endif // SRSRAN_ENB_DL_NR_H

@ -0,0 +1,79 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_GNB_DL_H
#define SRSRAN_GNB_DL_H
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/dft/ofdm.h"
#include "srsran/phy/phch/pdcch_cfg_nr.h"
#include "srsran/phy/phch/pdcch_nr.h"
#include "srsran/phy/phch/pdsch_nr.h"
typedef struct SRSRAN_API {
srsran_pdsch_nr_args_t pdsch;
srsran_pdcch_nr_args_t pdcch;
uint32_t nof_tx_antennas;
uint32_t nof_max_prb;
} srsran_gnb_dl_args_t;
typedef struct SRSRAN_API {
uint32_t max_prb;
uint32_t nof_tx_antennas;
srsran_carrier_nr_t carrier;
srsran_pdcch_cfg_nr_t pdcch_cfg;
srsran_ofdm_t fft[SRSRAN_MAX_PORTS];
cf_t* sf_symbols[SRSRAN_MAX_PORTS];
srsran_pdsch_nr_t pdsch;
srsran_dmrs_sch_t dmrs;
srsran_dci_nr_t dci; ///< Stores DCI configuration
srsran_pdcch_nr_t pdcch;
} srsran_gnb_dl_t;
SRSRAN_API int srsran_gnb_dl_init(srsran_gnb_dl_t* q, cf_t* output[SRSRAN_MAX_PORTS], const srsran_gnb_dl_args_t* args);
SRSRAN_API int srsran_gnb_dl_set_carrier(srsran_gnb_dl_t* q, const srsran_carrier_nr_t* carrier);
SRSRAN_API int srsran_gnb_dl_set_pdcch_config(srsran_gnb_dl_t* q,
const srsran_pdcch_cfg_nr_t* cfg,
const srsran_dci_cfg_nr_t* dci_cfg);
SRSRAN_API void srsran_gnb_dl_free(srsran_gnb_dl_t* q);
SRSRAN_API int srsran_gnb_dl_base_zero(srsran_gnb_dl_t* q);
SRSRAN_API void srsran_gnb_dl_gen_signal(srsran_gnb_dl_t* q);
SRSRAN_API int
srsran_gnb_dl_pdcch_put_dl(srsran_gnb_dl_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_dl_nr_t* dci_dl);
SRSRAN_API int
srsran_gnb_dl_pdcch_put_ul(srsran_gnb_dl_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_ul_nr_t* dci_ul);
SRSRAN_API int srsran_gnb_dl_pdsch_put(srsran_gnb_dl_t* q,
const srsran_slot_cfg_t* slot,
const srsran_sch_cfg_nr_t* cfg,
uint8_t* data[SRSRAN_MAX_TB]);
SRSRAN_API int
srsran_gnb_dl_pdsch_info(const srsran_gnb_dl_t* q, const srsran_sch_cfg_nr_t* cfg, char* str, uint32_t str_len);
SRSRAN_API int
srsran_gnb_dl_pdcch_dl_info(const srsran_gnb_dl_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
SRSRAN_API int
srsran_gnb_dl_pdcch_ul_info(const srsran_gnb_dl_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len);
#endif // SRSRAN_GNB_DL_H

@ -0,0 +1,74 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_GNB_UL_H
#define SRSRAN_GNB_UL_H
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/dft/ofdm.h"
#include "srsran/phy/phch/pucch_nr.h"
#include "srsran/phy/phch/pusch_nr.h"
typedef struct SRSRAN_API {
srsran_pusch_nr_args_t pusch;
srsran_pucch_nr_args_t pucch;
uint32_t nof_max_prb;
} srsran_gnb_ul_args_t;
typedef struct SRSRAN_API {
uint32_t max_prb;
srsran_carrier_nr_t carrier;
srsran_ofdm_t fft;
cf_t* sf_symbols[SRSRAN_MAX_PORTS];
srsran_pusch_nr_t pusch;
srsran_pucch_nr_t pucch;
srsran_dmrs_sch_t dmrs;
srsran_chest_dl_res_t chest_pusch;
srsran_chest_ul_res_t chest_pucch;
} srsran_gnb_ul_t;
SRSRAN_API int srsran_gnb_ul_init(srsran_gnb_ul_t* q, cf_t* input, const srsran_gnb_ul_args_t* args);
SRSRAN_API void srsran_gnb_ul_free(srsran_gnb_ul_t* q);
SRSRAN_API int srsran_gnb_ul_set_carrier(srsran_gnb_ul_t* q, const srsran_carrier_nr_t* carrier);
SRSRAN_API int srsran_gnb_ul_fft(srsran_gnb_ul_t* q);
SRSRAN_API int srsran_gnb_ul_get_pusch(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
srsran_pusch_res_nr_t* data);
SRSRAN_API int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_uci_value_nr_t* uci_value);
SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len);
SRSRAN_API uint32_t srsran_gnb_ul_pusch_info(srsran_gnb_ul_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len);
#endif // SRSRAN_GNB_UL_H

@ -0,0 +1,40 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_HARQ_ACK_H
#define SRSRAN_HARQ_ACK_H
#include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/phch/harq_ack_cfg.h"
#include "srsran/phy/phch/uci_cfg_nr.h"
SRSRAN_API int srsran_harq_ack_resource(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_harq_ack_resource_t* pdsch_ack_resource);
SRSRAN_API int srsran_harq_ack_gen_uci_cfg(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_cfg_nr_t* uci_cfg);
SRSRAN_API int srsran_harq_ack_pack(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data);
SRSRAN_API int srsran_harq_ack_unpack(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_uci_data_nr_t* uci_data,
srsran_pdsch_ack_nr_t* ack_info);
SRSRAN_API int srsran_harq_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, const srsran_harq_ack_m_t* m);
SRSRAN_API uint32_t srsran_harq_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len);
#endif // SRSRAN_HARQ_ACK_H

@ -0,0 +1,107 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_HARQ_ACK_CFG_H
#define SRSRAN_HARQ_ACK_CFG_H
#include "srsran/phy/common/phy_common_nr.h"
#include <stdbool.h>
#include <stdint.h>
/**
* @brief Maximum number of HARQ ACK feedback bits that can be carried in Uplink Control Information (UCI) message
*/
#define SRSRAN_HARQ_ACK_MAX_NOF_BITS 360
/**
* @brief Describes a HARQ ACK resource configuration
*/
typedef struct {
uint32_t scell_idx; ///< Serving cell index
uint32_t v_dai_dl; ///< Downlink Assigment Index
bool dci_format_1_1; ///< Set to true if the PDSCH transmission is triggered by a PDCCH DCI format 1_1 transmission
uint32_t k1; ///< HARQ feedback timing
uint32_t pid; ///< HARQ process identifier
uint16_t rnti;
uint32_t pucch_resource_id;
} srsran_harq_ack_resource_t;
/**
* @brief Describes a single PDSCH transmission HARQ ACK feedback
*/
typedef struct {
srsran_harq_ack_resource_t resource;
uint8_t value[SRSRAN_MAX_CODEWORDS]; // 0/1 or 2 for DTX
bool present; // set to true if there is a PDSCH on serving cell c associated with PDCCH in PDCCH monitoring occasion
// m, or there is a PDCCH indicating SPS PDSCH release on serving cell c
bool dl_bwp_changed; // set to true if PDCCH monitoring occasion m is before an active DL BWP change on serving cell c
bool ul_bwp_changed; // set to true if an active UL BWP change on the PCell and an active DL BWP change is not
// triggered by a DCI format 1_1 in PDCCH monitoring occasion m
bool second_tb_present; // set to true if two TB were detected in the PDCCH monitoring occasion m
} srsran_harq_ack_m_t;
#define SRSRAN_UCI_NR_MAX_M 10
/**
* @brief Describes a collection of PDSCH HARQ ACK feedback for a number of PDSCH transmissions within a component
* carrier
*/
typedef struct {
uint32_t M;
srsran_harq_ack_m_t m[SRSRAN_UCI_NR_MAX_M];
} srsran_harq_ack_cc_t;
/**
* @brief Describes a collection of PDSCH HARQ ACK feedback for a number of component carriers
*/
typedef struct {
srsran_harq_ack_cc_t cc[SRSRAN_MAX_CARRIERS];
uint32_t nof_cc;
bool use_pusch; // Set to true, if UCI bits are carried by PUSCH
} srsran_pdsch_ack_nr_t;
/**
* @brief Describes higher layer HARQ ACK feedback for PDSCH configuration
*/
typedef struct SRSRAN_API {
bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided
bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided
srsran_harq_ack_codebook_t harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration
bool max_cw_sched_dci_is_2; ///< Param maxNrofCodeWordsScheduledByDCI, set to true if present and equal to 2
uint32_t dl_data_to_ul_ack[SRSRAN_MAX_NOF_DL_DATA_TO_UL];
uint32_t nof_dl_data_to_ul_ack;
} srsran_harq_ack_cfg_hl_t;
/**
* @brief Describes HARQ ACK bit configuration for UCI encoding/decoding
* @note if tb0 and tb1 are false, the HARQ ACK bit is not used
* @note if tb0 and tb1 are true, the HARQ ACK feedback are bundled, the actual HARQ ACK feedback bit is the result of
* the AND operation
*/
typedef struct SRSRAN_API {
bool tb0; ///< Set to true if this ACK bit is mapped into TB index 0
bool tb1; ///< Set to true if this ACK bit is mapped into TB index 1
uint32_t cc_idx; ///< Component carrier index
uint32_t m_idx; ///< M resource index for packing/unpacking
uint32_t pid; ///< HARQ process identifier
} srsran_harq_ack_bit_t;
/**
* @brief Describes HARQ ACK feedback configuration for UCI encoding/decoding
*/
typedef struct SRSRAN_API {
srsran_harq_ack_bit_t bits[SRSRAN_HARQ_ACK_MAX_NOF_BITS]; ///< HARQ-ACK feedback bits
uint32_t count; ///< Number of ACK bits
} srsran_harq_ack_cfg_t;
#endif // SRSRAN_HARQ_ACK_CFG_H

@ -197,6 +197,7 @@ SRSRAN_API int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t*
* @param[in] slot_symbols Resource grid of the given slot * @param[in] slot_symbols Resource grid of the given slot
* @param[out] b Bits to decode * @param[out] b Bits to decode
* @param[in] nof_bits Number of bits to decode in the message * @param[in] nof_bits Number of bits to decode in the message
* @param[out] norm_corr Normalised correlation
* @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise
*/ */
SRSRAN_API int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q, SRSRAN_API int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
@ -206,7 +207,8 @@ SRSRAN_API int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t*
srsran_chest_ul_res_t* chest_res, srsran_chest_ul_res_t* chest_res,
cf_t* slot_symbols, cf_t* slot_symbols,
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS], uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS],
uint32_t nof_bits); uint32_t nof_bits,
float* norm_corr);
/** /**
* @brief Encoder NR-PUCCH formats 2, 3 and 4. The NR-PUCCH format is selected by resource->format. * @brief Encoder NR-PUCCH formats 2, 3 and 4. The NR-PUCCH format is selected by resource->format.
@ -248,9 +250,9 @@ SRSRAN_API int srsran_pucch_nr_format_2_3_4_decode(srsran_pucch_nr_t*
cf_t* slot_symbols, cf_t* slot_symbols,
srsran_uci_value_nr_t* uci_value); srsran_uci_value_nr_t* uci_value);
SRSRAN_API uint32_t srsran_pucch_nr_tx_info(const srsran_pucch_nr_resource_t* resource, SRSRAN_API uint32_t srsran_pucch_nr_info(const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data, const srsran_uci_data_nr_t* uci_data,
char* str, char* str,
uint32_t str_len); uint32_t str_len);
#endif // SRSRAN_PUCCH_NR_H #endif // SRSRAN_PUCCH_NR_H

@ -113,7 +113,7 @@ SRSRAN_API int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
srsran_chest_dl_res_t* channel, srsran_chest_dl_res_t* channel,
cf_t* sf_symbols[SRSRAN_MAX_PORTS], cf_t* sf_symbols[SRSRAN_MAX_PORTS],
srsran_pusch_res_nr_t* data[SRSRAN_MAX_TB]); srsran_pusch_res_nr_t* data);
SRSRAN_API uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q, SRSRAN_API uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,

@ -120,6 +120,7 @@ SRSRAN_API int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrie
* Note: Only TypeA PUSCH mapping type is supported * Note: Only TypeA PUSCH mapping type is supported
* *
* @param carrier Carrier information struct * @param carrier Carrier information struct
* @param slot Slot configuration
* @param pusch_hl_cfg PUSCH configuration provided by higher layers * @param pusch_hl_cfg PUSCH configuration provided by higher layers
* @param dci_ul DCI uplink (format 0_0 or 0_1) * @param dci_ul DCI uplink (format 0_0 or 0_1)
* @param pusch_cfg PUSCH configuration after applying the procedure * @param pusch_cfg PUSCH configuration after applying the procedure
@ -127,6 +128,7 @@ SRSRAN_API int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrie
* @return 0 on success, -1 on error * @return 0 on success, -1 on error
*/ */
SRSRAN_API int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, SRSRAN_API int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot,
const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
const srsran_dci_ul_nr_t* dci_ul, const srsran_dci_ul_nr_t* dci_ul,
srsran_sch_cfg_nr_t* pusch_cfg, srsran_sch_cfg_nr_t* pusch_cfg,

@ -37,7 +37,8 @@ typedef struct SRSRAN_API {
uint32_t N_L; ///< the number of transmission layers that the transport block is mapped onto uint32_t N_L; ///< the number of transmission layers that the transport block is mapped onto
uint32_t mcs; ///< Modulation Code Scheme (MCS) for debug and trace purpose uint32_t mcs; ///< Modulation Code Scheme (MCS) for debug and trace purpose
int tbs; ///< Payload size, TS 38.212 refers to it as A int tbs; ///< Payload size, TS 38.212 refers to it as A
double R; ///< Target LDPC rate double R; ///< Target code rate
double R_prime; ///< Actual code rate
int rv; ///< Redundancy version int rv; ///< Redundancy version
int ndi; ///< New Data Indicator int ndi; ///< New Data Indicator
uint32_t nof_re; ///< Number of available resource elements to transmit ULSCH (data) and UCI (control) uint32_t nof_re; ///< Number of available resource elements to transmit ULSCH (data) and UCI (control)

@ -23,6 +23,7 @@
#define SRSRAN_UCI_CFG_NR_H #define SRSRAN_UCI_CFG_NR_H
#include "csi_cfg.h" #include "csi_cfg.h"
#include "harq_ack_cfg.h"
#include "srsran/phy/common/phy_common_nr.h" #include "srsran/phy/common/phy_common_nr.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -33,11 +34,6 @@
*/ */
#define SRSRAN_UCI_NR_MAX_NOF_BITS 1706U #define SRSRAN_UCI_NR_MAX_NOF_BITS 1706U
/**
* @brief Maximum number of HARQ ACK feedback bits that can be carried in Uplink Control Information (UCI) message
*/
#define SRSRAN_UCI_NR_MAX_ACK_BITS 360
/** /**
* @brief Maximum number of Channel State Information part 1 (CSI1) bits that can be carried in Uplink Control * @brief Maximum number of Channel State Information part 1 (CSI1) bits that can be carried in Uplink Control
* Information (UCI) message * Information (UCI) message
@ -81,7 +77,7 @@ typedef struct {
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
/// Common Parameters /// Common Parameters
uint32_t o_ack; ///< Number of HARQ-ACK bits srsran_harq_ack_cfg_t ack; ///< HARQ-ACK configuration
uint32_t o_sr; ///< Number of SR bits uint32_t o_sr; ///< Number of SR bits
srsran_csi_report_cfg_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< CSI report configuration srsran_csi_report_cfg_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
uint32_t nof_csi; ///< Number of CSI reports uint32_t nof_csi; ///< Number of CSI reports
@ -95,9 +91,9 @@ typedef struct SRSRAN_API {
* @brief Uplink Control Information (UCI) message packed information * @brief Uplink Control Information (UCI) message packed information
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
uint8_t ack[SRSRAN_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits uint8_t ack[SRSRAN_HARQ_ACK_MAX_NOF_BITS]; ///< HARQ ACK feedback bits
uint32_t sr; ///< Number of positive SR uint32_t sr; ///< Number of positive SR
srsran_csi_report_value_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< Packed CSI report values srsran_csi_report_value_t csi[SRSRAN_CSI_MAX_NOF_REPORT]; ///< Packed CSI report values
bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter
} srsran_uci_value_nr_t; } srsran_uci_value_nr_t;

@ -47,49 +47,6 @@ typedef struct SRSRAN_API {
float pdcch_dmrs_epre_thr; float pdcch_dmrs_epre_thr;
} srsran_ue_dl_nr_args_t; } srsran_ue_dl_nr_args_t;
typedef struct {
uint32_t scell_idx; ///< Serving cell index
uint32_t v_dai_dl; ///< Downlink Assigment Index
bool dci_format_1_1; ///< Set to true if the PDSCH transmission is triggered by a PDCCH DCI format 1_1 transmission
uint32_t k1; ///< HARQ feedback timing
uint16_t rnti;
uint32_t pucch_resource_id;
} srsran_pdsch_ack_resource_nr_t;
typedef struct {
srsran_pdsch_ack_resource_nr_t resource;
uint8_t value[SRSRAN_MAX_CODEWORDS]; // 0/1 or 2 for DTX
bool present; // set to true if there is a PDSCH on serving cell c associated with PDCCH in PDCCH monitoring occasion
// m, or there is a PDCCH indicating SPS PDSCH release on serving cell c
bool dl_bwp_changed; // set to true if PDCCH monitoring occasion m is before an active DL BWP change on serving cell c
bool ul_bwp_changed; // set to true if an active UL BWP change on the PCell and an active DL BWP change is not
// triggered by a DCI format 1_1 in PDCCH monitoring occasion m
bool second_tb_present; // set to true if two TB were detected in the PDCCH monitoring occasion m
} srsran_pdsch_ack_m_nr_t;
#define SRSRAN_UCI_NR_MAX_M 10
typedef struct {
uint32_t M;
srsran_pdsch_ack_m_nr_t m[SRSRAN_UCI_NR_MAX_M];
} srsran_pdsch_ack_cc_nr_t;
typedef struct {
srsran_pdsch_ack_cc_nr_t cc[SRSRAN_MAX_CARRIERS];
uint32_t nof_cc;
bool use_pusch; // Set to true, if UCI bits are carried by PUSCH
} srsran_pdsch_ack_nr_t;
typedef struct SRSRAN_API {
bool harq_ack_spatial_bundling_pucch; ///< Param harq-ACK-SpatialBundlingPUCCH, set to true if provided
bool harq_ack_spatial_bundling_pusch; ///< Param harq-ACK-SpatialBundlingPUSCH, set to true if provided
srsran_harq_ack_codebook_t harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration
bool max_cw_sched_dci_is_2; ///< Param maxNrofCodeWordsScheduledByDCI, set to true if present and equal to 2
uint32_t dl_data_to_ul_ack[SRSRAN_MAX_NOF_DL_DATA_TO_UL];
uint32_t nof_dl_data_to_ul_ack;
} srsran_ue_dl_nr_harq_ack_cfg_t;
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
srsran_dci_ctx_t dci_ctx; srsran_dci_ctx_t dci_ctx;
srsran_dmrs_pdcch_measure_t measure; srsran_dmrs_pdcch_measure_t measure;
@ -170,18 +127,6 @@ SRSRAN_API int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q,
char* str, char* str,
uint32_t str_len); uint32_t str_len);
SRSRAN_API int srsran_ue_dl_nr_pdsch_ack_resource(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_pdsch_ack_resource_nr_t* pdsch_ack_resource);
SRSRAN_API int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data);
SRSRAN_API int srsran_ue_dl_nr_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, const srsran_pdsch_ack_m_nr_t* m);
SRSRAN_API uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len);
SRSRAN_API SRSRAN_API
int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q, int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q,
const srsran_slot_cfg_t* slot_cfg, const srsran_slot_cfg_t* slot_cfg,

@ -77,7 +77,7 @@ SRSRAN_API extern int handler_registered;
#define ERROR(_fmt, ...) \ #define ERROR(_fmt, ...) \
do { \ do { \
if (!handler_registered) { \ if (!handler_registered) { \
fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); \ fprintf(stderr, "\e[31m%s:%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); \
} else { \ } else { \
srsran_phy_log_print(LOG_LEVEL_ERROR_S, _fmt, ##__VA_ARGS__); \ srsran_phy_log_print(LOG_LEVEL_ERROR_S, _fmt, ##__VA_ARGS__); \
} \ } \

@ -493,7 +493,6 @@ private:
int get_status_pdu_length(); int get_status_pdu_length();
int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes); int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes);
bool get_do_status(); bool get_do_status();
void reset_status(); // called when status PDU has been sent
private: private:
void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header);
@ -503,6 +502,7 @@ private:
void debug_state(); void debug_state();
void print_rx_segments(); void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment);
void reset_status();
rlc_am_lte* parent = nullptr; rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
@ -536,8 +536,8 @@ private:
rlc_ringbuffer_t<rlc_amd_rx_pdu> rx_window; rlc_ringbuffer_t<rlc_amd_rx_pdu> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments; std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
bool poll_received = false; bool poll_received = false;
bool do_status = false; std::atomic<bool> do_status = {false}; // light-weight access from Tx entity
/**************************************************************************** /****************************************************************************
* Timers * Timers

@ -94,6 +94,7 @@ extern "C" {
#include "srsran/phy/phch/csi.h" #include "srsran/phy/phch/csi.h"
#include "srsran/phy/phch/dci.h" #include "srsran/phy/phch/dci.h"
#include "srsran/phy/phch/dci_nr.h" #include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/phch/harq_ack.h"
#include "srsran/phy/phch/pbch.h" #include "srsran/phy/phch/pbch.h"
#include "srsran/phy/phch/pbch_nr.h" #include "srsran/phy/phch/pbch_nr.h"
#include "srsran/phy/phch/pcfich.h" #include "srsran/phy/phch/pcfich.h"
@ -125,8 +126,9 @@ extern "C" {
#include "srsran/phy/ue/ue_ul_nr.h" #include "srsran/phy/ue/ue_ul_nr.h"
#include "srsran/phy/enb/enb_dl.h" #include "srsran/phy/enb/enb_dl.h"
#include "srsran/phy/enb/enb_dl_nr.h"
#include "srsran/phy/enb/enb_ul.h" #include "srsran/phy/enb/enb_ul.h"
#include "srsran/phy/gnb/gnb_dl.h"
#include "srsran/phy/gnb/gnb_ul.h"
#include "srsran/phy/scrambling/scrambling.h" #include "srsran/phy/scrambling/scrambling.h"

@ -73,5 +73,10 @@ add_library(ngap_nr_asn1 STATIC ngap.cc)
target_compile_options(ngap_nr_asn1 PRIVATE "-Os") target_compile_options(ngap_nr_asn1 PRIVATE "-Os")
target_link_libraries(ngap_nr_asn1 asn1_utils srsran_common) target_link_libraries(ngap_nr_asn1 asn1_utils srsran_common)
INSTALL(TARGETS ngap_nr_asn1 DESTINATION ${LIBRARY_DIR}) INSTALL(TARGETS ngap_nr_asn1 DESTINATION ${LIBRARY_DIR})
# NAS 5G
add_library(nas_5g_msg STATIC nas_5g_msg.cc nas_5g_ies.cc nas_5g_utils.cc)
target_compile_options(nas_5g_msg PRIVATE "-Os")
target_link_libraries(nas_5g_msg asn1_utils srsran_common)
INSTALL(TARGETS nas_5g_msg DESTINATION ${LIBRARY_DIR})

@ -246,15 +246,20 @@ SRSASN_CODE bit_ref_impl<Ptr>::unpack_bytes(uint8_t* buf, uint32_t n_bytes)
if (n_bytes == 0) { if (n_bytes == 0) {
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
if (ptr + n_bytes >= max_ptr) {
log_error("Buffer size limit was achieved");
return SRSASN_ERROR_DECODE_FAIL;
}
if (offset == 0) { if (offset == 0) {
// Aligned case // Aligned case
if (ptr + n_bytes > max_ptr) {
log_error("Buffer size limit was achieved");
return SRSASN_ERROR_DECODE_FAIL;
}
memcpy(buf, ptr, n_bytes); memcpy(buf, ptr, n_bytes);
ptr += n_bytes; ptr += n_bytes;
} else { } else {
// Unaligned case
if (ptr + n_bytes >= max_ptr) {
log_error("Buffer size limit was achieved");
return SRSASN_ERROR_DECODE_FAIL;
}
for (uint32_t i = 0; i < n_bytes; ++i) { for (uint32_t i = 0; i < n_bytes; ++i) {
HANDLE_CODE(unpack(buf[i], 8)); HANDLE_CODE(unpack(buf[i], 8));
} }
@ -283,7 +288,7 @@ SRSASN_CODE bit_ref_impl<Ptr>::advance_bits(uint32_t n_bits)
uint32_t bytes_required = ceilf((offset + n_bits) / 8.0f); uint32_t bytes_required = ceilf((offset + n_bits) / 8.0f);
uint32_t bytes_offset = floorf((offset + n_bits) / 8.0f); uint32_t bytes_offset = floorf((offset + n_bits) / 8.0f);
if (ptr + bytes_required >= max_ptr) { if (ptr + bytes_required > max_ptr) {
log_error("Buffer size limit was achieved"); log_error("Buffer size limit was achieved");
return SRSASN_ERROR_DECODE_FAIL; return SRSASN_ERROR_DECODE_FAIL;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,56 @@
/**
*
* \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 "srsran/asn1/nas_5g_utils.h"
#include "srsran/asn1/asn1_utils.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h"
#include "srsran/config.h"
#include <array>
#include <stdint.h>
#include <vector>
namespace srsran {
namespace nas_5g {
SRSASN_CODE unpack_mcc_mnc(uint8_t* mcc_bytes, uint8_t* mnc_bytes, asn1::cbit_ref& bref)
{
// MCC digit 2 | MCC digit 1 | octet 5
// MNC digit 3 | MCC digit 3 | octet 6
// MNC digit 2 | MNC digit 1 | octet 7
HANDLE_CODE(bref.unpack(mcc_bytes[1], 4));
HANDLE_CODE(bref.unpack(mcc_bytes[0], 4));
HANDLE_CODE(bref.unpack(mnc_bytes[2], 4));
HANDLE_CODE(bref.unpack(mcc_bytes[2], 4));
HANDLE_CODE(bref.unpack(mnc_bytes[1], 4));
HANDLE_CODE(bref.unpack(mnc_bytes[0], 4));
return SRSASN_SUCCESS;
}
SRSASN_CODE pack_mcc_mnc(uint8_t* mcc_bytes, uint8_t* mnc_bytes, asn1::bit_ref& bref)
{
// MCC digit 2 | MCC digit 1 | octet 5
// MNC digit 3 | MCC digit 3 | octet 6
// MNC digit 2 | MNC digit 1 | octet 7
HANDLE_CODE(bref.pack(mcc_bytes[1], 4));
HANDLE_CODE(bref.pack(mcc_bytes[0], 4));
HANDLE_CODE(bref.pack(mnc_bytes[2], 4));
HANDLE_CODE(bref.pack(mcc_bytes[2], 4));
HANDLE_CODE(bref.pack(mnc_bytes[1], 4));
HANDLE_CODE(bref.pack(mnc_bytes[0], 4));
return SRSASN_SUCCESS;
}
} // namespace nas_5g
} // namespace srsran

@ -4493,61 +4493,6 @@ uint8_t sib_type_info_s::type_opts::to_number() const
return map_enum_number(options, 8, value, "sib_type_info_s::type_e_"); return map_enum_number(options, 8, value, "sib_type_info_s::type_e_");
} }
// SetupRelease{ElementTypeParam} ::= CHOICE
template <class elem_type_paramT_>
void setup_release_c<elem_type_paramT_>::set(typename types::options e)
{
type_ = e;
}
template <class elem_type_paramT_>
void setup_release_c<elem_type_paramT_>::to_json(json_writer& j) const
{
j.start_obj();
switch (type_) {
case types::release:
break;
case types::setup:
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
}
j.end_obj();
}
template <class elem_type_paramT_>
SRSASN_CODE setup_release_c<elem_type_paramT_>::pack(bit_ref& bref) const
{
type_.pack(bref);
switch (type_) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.pack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_ENCODE_FAIL;
}
return SRSASN_SUCCESS;
}
template <class elem_type_paramT_>
SRSASN_CODE setup_release_c<elem_type_paramT_>::unpack(cbit_ref& bref)
{
types e;
e.unpack(bref);
set(e);
switch (type_) {
case types::release:
break;
case types::setup:
HANDLE_CODE(c.unpack(bref));
break;
default:
log_invalid_choice_id(type_, "setup_release_c");
return SRSASN_ERROR_DECODE_FAIL;
}
return SRSASN_SUCCESS;
}
// UAC-BarringPerCat ::= SEQUENCE // UAC-BarringPerCat ::= SEQUENCE
SRSASN_CODE uac_barr_per_cat_s::pack(bit_ref& bref) const SRSASN_CODE uac_barr_per_cat_s::pack(bit_ref& bref) const
{ {

@ -351,10 +351,10 @@ bool make_phy_tdd_cfg(const tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common,
return true; return true;
} }
bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg, bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg,
srsran_ue_dl_nr_harq_ack_cfg_t* in_srsran_ue_dl_nr_harq_ack_cfg) srsran_harq_ack_cfg_hl_t* in_srsran_ue_dl_nr_harq_ack_cfg)
{ {
srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg = {}; srsran_harq_ack_cfg_hl_t srsran_ue_dl_nr_harq_ack_cfg = {};
switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) { switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) {
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value: case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value:
srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;

@ -34,6 +34,8 @@ set(SOURCES arch_select.cc
network_utils.cc network_utils.cc
mac_pcap_net.cc mac_pcap_net.cc
pcap.c pcap.c
phy_cfg_nr.cc
phy_cfg_nr_default.cc
rlc_pcap.cc rlc_pcap.cc
s1ap_pcap.cc s1ap_pcap.cc
security.cc security.cc

@ -468,7 +468,7 @@ void socket_manager::run_thread()
FD_SET(pipefd[0], &total_fd_set); FD_SET(pipefd[0], &total_fd_set);
max_fd = std::max(pipefd[0], max_fd); max_fd = std::max(pipefd[0], max_fd);
while (running) { while (running.load(std::memory_order_relaxed)) {
memcpy(&read_fd_set, &total_fd_set, sizeof(total_fd_set)); memcpy(&read_fd_set, &total_fd_set, sizeof(total_fd_set));
int n = select(max_fd + 1, &read_fd_set, nullptr, nullptr, nullptr); int n = select(max_fd + 1, &read_fd_set, nullptr, nullptr, nullptr);

@ -0,0 +1,327 @@
/**
*
* \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 "srsran/common/phy_cfg_nr.h"
#include "srsran/srsran.h"
namespace srsran {
srsran_dci_cfg_nr_t phy_cfg_nr_t::get_dci_cfg() const
{
srsran_dci_cfg_nr_t dci_cfg = {};
// Assume BWP bandwidth equals full channel bandwidth
dci_cfg.coreset0_bw = pdcch.coreset_present[0] ? srsran_coreset_get_bw(&pdcch.coreset[0]) : 0;
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_dl_active_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_active_bw = carrier.nof_prb;
// Iterate over all SS to select monitoring options
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; i++) {
// Skip not configured SS
if (not pdcch.search_space_present[i]) {
continue;
}
// Iterate all configured formats
for (uint32_t j = 0; j < pdcch.search_space[i].nof_formats; j++) {
if (pdcch.search_space[i].type == srsran_search_space_type_common_3 &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) {
dci_cfg.monitor_common_0_0 = true;
} else if (pdcch.search_space[i].type == srsran_search_space_type_ue &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_0) {
dci_cfg.monitor_0_0_and_1_0 = true;
} else if (pdcch.search_space[i].type == srsran_search_space_type_ue &&
pdcch.search_space[i].formats[j] == srsran_dci_format_nr_0_1) {
dci_cfg.monitor_0_1_and_1_1 = true;
}
}
}
// Set PUSCH parameters
dci_cfg.enable_sul = false;
dci_cfg.enable_hopping = false;
// Set Format 0_1 and 1_1 parameters
dci_cfg.carrier_indicator_size = 0;
dci_cfg.harq_ack_codebok = harq_ack.harq_ack_codebook;
dci_cfg.nof_rb_groups = 0;
// Format 0_1 specific configuration (for PUSCH only)
dci_cfg.nof_ul_bwp = 0;
dci_cfg.nof_ul_time_res = (pusch.nof_dedicated_time_ra > 0)
? pusch.nof_dedicated_time_ra
: (pusch.nof_common_time_ra > 0) ? pusch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA;
dci_cfg.nof_srs = 1;
dci_cfg.nof_ul_layers = 1;
dci_cfg.pusch_nof_cbg = 0;
dci_cfg.report_trigger_size = 0;
dci_cfg.enable_transform_precoding = false;
dci_cfg.dynamic_dual_harq_ack_codebook = false;
dci_cfg.pusch_tx_config_non_codebook = false;
dci_cfg.pusch_ptrs = false;
dci_cfg.pusch_dynamic_betas = false;
dci_cfg.pusch_alloc_type = pusch.alloc;
dci_cfg.pusch_dmrs_type = pusch.dmrs_type;
dci_cfg.pusch_dmrs_max_len = pusch.dmrs_max_length;
// Format 1_1 specific configuration (for PDSCH only)
dci_cfg.nof_dl_bwp = 0;
dci_cfg.nof_dl_time_res = (pdsch.nof_dedicated_time_ra > 0)
? pdsch.nof_dedicated_time_ra
: (pdsch.nof_common_time_ra > 0) ? pdsch.nof_common_time_ra : SRSRAN_MAX_NOF_TIME_RA;
dci_cfg.nof_aperiodic_zp = 0;
dci_cfg.pdsch_nof_cbg = 0;
dci_cfg.nof_dl_to_ul_ack = harq_ack.nof_dl_data_to_ul_ack;
dci_cfg.pdsch_inter_prb_to_prb = false;
dci_cfg.pdsch_rm_pattern1 = false;
dci_cfg.pdsch_rm_pattern2 = false;
dci_cfg.pdsch_2cw = false;
dci_cfg.multiple_scell = false;
dci_cfg.pdsch_tci = false;
dci_cfg.pdsch_cbg_flush = false;
dci_cfg.pdsch_dynamic_bundling = false;
dci_cfg.pdsch_alloc_type = pdsch.alloc;
dci_cfg.pdsch_dmrs_type = pdsch.dmrs_type;
dci_cfg.pdsch_dmrs_max_len = pdsch.dmrs_max_length;
return dci_cfg;
}
bool phy_cfg_nr_t::assert_ss_id(uint32_t ss_id) const
{
// Make sure SS access if bounded
if (ss_id > SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE) {
return false;
}
// Check SS is present
if (not pdcch.search_space_present[ss_id]) {
return false;
}
// Extract CORESET id
uint32_t coreset_id = pdcch.search_space[ss_id].coreset_id;
// Make sure CORESET id is bounded
if (coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET) {
return false;
}
// Check CORESET is present
if (not pdcch.coreset_present[coreset_id]) {
return false;
}
return true;
}
bool phy_cfg_nr_t::get_dci_locations(
const uint32_t& slot_idx,
const uint16_t& rnti,
const uint32_t& ss_id,
const uint32_t& L,
srsran::bounded_vector<srsran_dci_location_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>& locations) const
{
// Assert search space
if (not assert_ss_id(ss_id)) {
return SRSRAN_ERROR;
}
// Select SS and CORESET
const srsran_search_space_t& ss = pdcch.search_space[ss_id];
const srsran_coreset_t& coreset = pdcch.coreset[ss.coreset_id];
// Compute NCCE
std::array<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR> ncce = {};
int n = srsran_pdcch_nr_locations_coreset(&coreset, &ss, rnti, L, slot_idx, ncce.data());
if (n < SRSRAN_SUCCESS) {
return false;
}
// Push locations
for (uint32_t i = 0; i < (uint32_t)n; i++) {
locations.push_back({L, ncce[i]});
}
return true;
}
srsran_dci_format_nr_t phy_cfg_nr_t::get_dci_format_pdsch(uint32_t ss_id) const
{
// Assert search space
if (not assert_ss_id(ss_id)) {
return SRSRAN_DCI_FORMAT_NR_COUNT;
}
// Select SS
const srsran_search_space_t& ss = pdcch.search_space[ss_id];
// Extract number of formats
uint32_t nof_formats = SRSRAN_MIN(ss.nof_formats, SRSRAN_DCI_FORMAT_NR_COUNT);
// Select DCI formats
for (uint32_t i = 0; i < nof_formats; i++) {
// Select DL format
if (ss.formats[i] == srsran_dci_format_nr_1_0 or ss.formats[i] == srsran_dci_format_nr_1_1) {
return ss.formats[i];
}
}
// If reached here, no valid DCI format is available
return SRSRAN_DCI_FORMAT_NR_COUNT;
}
srsran_dci_format_nr_t phy_cfg_nr_t::get_dci_format_pusch(uint32_t ss_id) const
{
// Assert search space
if (not assert_ss_id(ss_id)) {
return SRSRAN_DCI_FORMAT_NR_COUNT;
}
// Select SS
const srsran_search_space_t& ss = pdcch.search_space[ss_id];
// Extract number of formats
uint32_t nof_formats = SRSRAN_MIN(ss.nof_formats, SRSRAN_DCI_FORMAT_NR_COUNT);
// Select DCI formats
for (uint32_t i = 0; i < nof_formats; i++) {
// Select DL format
if (ss.formats[i] == srsran_dci_format_nr_0_0 or ss.formats[i] == srsran_dci_format_nr_0_1) {
return ss.formats[i];
}
}
// If reached here, no valid DCI format is available
return SRSRAN_DCI_FORMAT_NR_COUNT;
}
bool phy_cfg_nr_t::get_dci_ctx_pdsch_rnti_c(uint32_t ss_id,
const srsran_dci_location_t& location,
const uint16_t& rnti,
srsran_dci_ctx_t& ctx) const
{
// Get DCI format, includes SS Id assertion
srsran_dci_format_nr_t format = get_dci_format_pdsch(ss_id);
if (format == SRSRAN_DCI_FORMAT_NR_COUNT) {
return false;
}
// Select search space
const srsran_search_space_t& ss = pdcch.search_space[ss_id];
// Fill context
ctx.location = location;
ctx.ss_type = ss.type;
ctx.coreset_id = ss.coreset_id;
ctx.rnti_type = srsran_rnti_type_c;
ctx.format = format;
ctx.rnti = rnti;
return true;
}
bool phy_cfg_nr_t::get_dci_ctx_pusch_rnti_c(uint32_t ss_id,
const srsran_dci_location_t& location,
const uint16_t& rnti,
srsran_dci_ctx_t& ctx) const
{
// Get DCI format, includes SS Id assertion
srsran_dci_format_nr_t format = get_dci_format_pusch(ss_id);
if (format == SRSRAN_DCI_FORMAT_NR_COUNT) {
return false;
}
// Select search space
const srsran_search_space_t& ss = pdcch.search_space[ss_id];
// Fill context
ctx.location = location;
ctx.ss_type = ss.type;
ctx.coreset_id = ss.coreset_id;
ctx.rnti_type = srsran_rnti_type_c;
ctx.format = format;
ctx.rnti = rnti;
return true;
}
bool phy_cfg_nr_t::get_pdsch_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_dci_dl_nr_t& dci,
srsran_sch_cfg_nr_t& pdsch_cfg) const
{
return srsran_ra_dl_dci_to_grant_nr(&carrier, &slot_cfg, &pdsch, &dci, &pdsch_cfg, &pdsch_cfg.grant) ==
SRSRAN_SUCCESS;
}
bool phy_cfg_nr_t::get_pusch_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_dci_ul_nr_t& dci,
srsran_sch_cfg_nr_t& pusch_cfg) const
{
return srsran_ra_ul_dci_to_grant_nr(&carrier, &slot_cfg, &pusch, &dci, &pusch_cfg, &pusch_cfg.grant) ==
SRSRAN_SUCCESS;
}
bool phy_cfg_nr_t::get_pdsch_ack_resource(const srsran_dci_dl_nr_t& dci_dl,
srsran_harq_ack_resource_t& ack_resource) const
{
return srsran_harq_ack_resource(&harq_ack, &dci_dl, &ack_resource) == SRSRAN_SUCCESS;
}
bool phy_cfg_nr_t::get_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_pdsch_ack_nr_t& pdsch_ack,
srsran_uci_cfg_nr_t& uci_cfg) const
{
// Generate configuration for HARQ feedback
if (srsran_harq_ack_gen_uci_cfg(&harq_ack, &pdsch_ack, &uci_cfg) < SRSRAN_SUCCESS) {
return false;
}
// Generate configuration for SR
// ...
// Generate configuration for CSI reports
// ...
return true;
}
bool phy_cfg_nr_t::get_pucch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_uci_cfg_nr_t& uci_cfg,
srsran_pucch_nr_common_cfg_t& cfg,
srsran_pucch_nr_resource_t& resource) const
{
// Select PUCCH resource
if (srsran_ra_ul_nr_pucch_resource(&pucch, &uci_cfg, &resource) < SRSRAN_SUCCESS) {
ERROR("Selecting PUCCH resource");
return false;
}
return true;
}
bool phy_cfg_nr_t::get_pusch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
const srsran_uci_cfg_nr_t& uci_cfg,
srsran_sch_cfg_nr_t& pusch_cfg) const
{
// Generate configuration for PUSCH
if (srsran_ra_ul_set_grant_uci_nr(&carrier, &pusch, &uci_cfg, &pusch_cfg) < SRSRAN_SUCCESS) {
return false;
}
return true;
}
} // namespace srsran

@ -0,0 +1,253 @@
/**
*
* \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 "srsran/common/phy_cfg_nr_default.h"
#include "srsran/srsran.h"
namespace srsran {
void phy_cfg_nr_default_t::make_carrier_custom_10MHz(srsran_carrier_nr_t& carrier)
{
carrier.nof_prb = 52;
carrier.max_mimo_layers = 1;
carrier.pci = 500;
carrier.absolute_frequency_point_a = 633928;
carrier.absolute_frequency_ssb = 634176;
carrier.offset_to_carrier = 0;
carrier.scs = srsran_subcarrier_spacing_15kHz;
}
void phy_cfg_nr_default_t::make_tdd_custom_6_4(srsran_tdd_config_nr_t& tdd)
{
tdd.pattern1.period_ms = 10;
tdd.pattern1.nof_dl_slots = 6;
tdd.pattern1.nof_dl_symbols = 0;
tdd.pattern1.nof_ul_slots = 4;
tdd.pattern1.nof_ul_symbols = 0;
// Disable pattern 2
tdd.pattern2.period_ms = 0;
}
void phy_cfg_nr_default_t::make_pdcch_custom_common_ss(srsran_pdcch_cfg_nr_t& pdcch, const srsran_carrier_nr_t& carrier)
{
// Configure CORESET ID 1
pdcch.coreset_present[1] = true;
pdcch.coreset[1].id = 1;
pdcch.coreset[1].duration = 1;
pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved;
pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
// Generate frequency resources for the full BW
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(carrier.nof_prb, 6);
}
// Configure Search Space 1 as common
pdcch.search_space_present[1] = true;
pdcch.search_space[1].id = 1;
pdcch.search_space[1].coreset_id = 1;
pdcch.search_space[1].duration = 1;
pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH
pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH
pdcch.search_space[1].nof_formats = 2;
pdcch.search_space[1].type = srsran_search_space_type_common_3;
// Generate 1 candidate for each aggregation level if possible
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
pdcch.search_space[1].nof_candidates[L] =
SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&pdcch.coreset[1], L));
}
}
void phy_cfg_nr_default_t::make_pdsch_default(srsran_sch_hl_cfg_nr_t& pdsch)
{
// Select PDSCH time resource allocation
pdsch.common_time_ra[0].k = 0;
pdsch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A;
pdsch.common_time_ra[0].sliv = srsran_ra_type2_to_riv(SRSRAN_NSYMB_PER_SLOT_NR - 1, 1, SRSRAN_NSYMB_PER_SLOT_NR);
pdsch.nof_common_time_ra = 1;
// Setup PDSCH DMRS type A position
pdsch.typeA_pos = srsran_dmrs_sch_typeA_pos_2;
}
void phy_cfg_nr_default_t::make_pusch_default(srsran_sch_hl_cfg_nr_t& pusch)
{
// Select PUSCH time resource allocation
pusch.common_time_ra[0].k = 4;
pusch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A;
pusch.common_time_ra[0].sliv = srsran_ra_type2_to_riv(SRSRAN_NSYMB_PER_SLOT_NR, 0, SRSRAN_NSYMB_PER_SLOT_NR);
pusch.nof_common_time_ra = 1;
// Setup PUSCH DMRS type A position
pusch.typeA_pos = srsran_dmrs_sch_typeA_pos_2;
pusch.scaling = 1.0f;
pusch.beta_offsets.fix_ack = 12.625f;
pusch.beta_offsets.fix_csi1 = 2.25f;
pusch.beta_offsets.fix_csi2 = 2.25f;
}
void phy_cfg_nr_default_t::make_pucch_custom_one(srsran_pucch_nr_hl_cfg_t& pucch)
{
// PUCCH Resource for format 1
srsran_pucch_nr_resource_t resource_small = {};
resource_small.starting_prb = 0;
resource_small.format = SRSRAN_PUCCH_NR_FORMAT_1;
resource_small.initial_cyclic_shift = 0;
resource_small.nof_symbols = 14;
resource_small.start_symbol_idx = 0;
resource_small.time_domain_occ = 0;
// PUCCH Resource for format 2
srsran_pucch_nr_resource_t resource_big = {};
resource_big.starting_prb = 51;
resource_big.format = SRSRAN_PUCCH_NR_FORMAT_2;
resource_big.nof_prb = 1;
resource_big.nof_symbols = 2;
resource_big.start_symbol_idx = 0;
// Resource for SR
srsran_pucch_nr_resource_t resource_sr = {};
resource_sr.starting_prb = 51;
resource_sr.format = SRSRAN_PUCCH_NR_FORMAT_1;
resource_sr.initial_cyclic_shift = 0;
resource_sr.nof_symbols = 14;
resource_sr.start_symbol_idx = 0;
resource_sr.time_domain_occ = 0;
pucch.enabled = true;
// Set format 1 for 1-2 bits
pucch.sets[0].resources[0] = resource_small;
pucch.sets[0].resources[1] = resource_small;
pucch.sets[0].resources[2] = resource_small;
pucch.sets[0].resources[3] = resource_small;
pucch.sets[0].resources[4] = resource_small;
pucch.sets[0].resources[5] = resource_small;
pucch.sets[0].resources[6] = resource_small;
pucch.sets[0].resources[7] = resource_small;
pucch.sets[0].nof_resources = 8;
// Set format 2 for more bits
pucch.sets[1].resources[0] = resource_big;
pucch.sets[1].resources[1] = resource_big;
pucch.sets[1].resources[2] = resource_big;
pucch.sets[1].resources[3] = resource_big;
pucch.sets[1].resources[4] = resource_big;
pucch.sets[1].resources[5] = resource_big;
pucch.sets[1].resources[6] = resource_big;
pucch.sets[1].resources[7] = resource_big;
pucch.sets[1].nof_resources = 8;
// Configure scheduling request
pucch.sr_resources[1].configured = true;
pucch.sr_resources[1].sr_id = 0;
pucch.sr_resources[1].period = 40;
pucch.sr_resources[1].offset = 8;
pucch.sr_resources[1].resource = resource_sr;
}
void phy_cfg_nr_default_t::make_harq_auto(srsran_harq_ack_cfg_hl_t& harq,
const srsran_carrier_nr_t& carrier,
const srsran_tdd_config_nr_t& tdd_cfg)
{
// Generate as many entries as DL slots
harq.nof_dl_data_to_ul_ack = SRSRAN_MAX(tdd_cfg.pattern1.nof_dl_slots, SRSRAN_MAX_NOF_DL_DATA_TO_UL);
// Set PDSCH to ACK timing delay to 4 or more
for (uint32_t n = 0; n < harq.nof_dl_data_to_ul_ack; n++) {
// Set the first slots into the first UL slot
if (n < (harq.nof_dl_data_to_ul_ack - 4)) {
harq.dl_data_to_ul_ack[n] = harq.nof_dl_data_to_ul_ack - n;
continue;
}
// After that try if n+4 is UL slot
if (srsran_tdd_nr_is_ul(&tdd_cfg, carrier.scs, n + 4)) {
harq.dl_data_to_ul_ack[n] = 4;
continue;
}
// Otherwise set delay to the first UL slot of the next TDD period
harq.dl_data_to_ul_ack[n] = 2 * harq.nof_dl_data_to_ul_ack - n;
}
// Zero the rest
for (uint32_t i = harq.nof_dl_data_to_ul_ack; i < SRSRAN_MAX_NOF_DL_DATA_TO_UL; i++) {
harq.dl_data_to_ul_ack[i] = 0;
}
// Select dynamic HARQ-ACK codebook
harq.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
}
void phy_cfg_nr_default_t::make_prach_default_lte(srsran_prach_cfg_t& prach)
{
prach.config_idx = 0;
prach.freq_offset = 2;
prach.root_seq_idx = 0;
}
phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
{
switch (reference_cfg.carrier) {
case reference_cfg_t::R_CARRIER_CUSTOM_10MHZ:
make_carrier_custom_10MHz(carrier);
break;
}
switch (reference_cfg.tdd) {
case reference_cfg_t::R_TDD_CUSTOM_6_4:
make_tdd_custom_6_4(tdd);
break;
}
switch (reference_cfg.pdcch) {
case reference_cfg_t::R_PDCCH_CUSTOM_COMMON_SS:
make_pdcch_custom_common_ss(pdcch, carrier);
break;
}
switch (reference_cfg.pdsch) {
case reference_cfg_t::R_PDSCH_DEFAULT:
make_pdsch_default(pdsch);
break;
}
switch (reference_cfg.pusch) {
case reference_cfg_t::R_PUSCH_DEFAULT:
make_pusch_default(pusch);
break;
}
switch (reference_cfg.pucch) {
case reference_cfg_t::R_PUCCH_CUSTOM_ONE:
make_pucch_custom_one(pucch);
break;
}
switch (reference_cfg.harq) {
case reference_cfg_t::R_HARQ_AUTO:
make_harq_auto(harq_ack, carrier, tdd);
break;
}
switch (reference_cfg.prach) {
case reference_cfg_t::R_PRACH_DEFAULT_LTE:
make_prach_default_lte(prach);
break;
}
}
} // namespace srsran

@ -35,6 +35,7 @@ add_subdirectory(resampling)
add_subdirectory(scrambling) add_subdirectory(scrambling)
add_subdirectory(ue) add_subdirectory(ue)
add_subdirectory(enb) add_subdirectory(enb)
add_subdirectory(gnb)
set(srsran_srcs $<TARGET_OBJECTS:srsran_agc> set(srsran_srcs $<TARGET_OBJECTS:srsran_agc>
$<TARGET_OBJECTS:srsran_ch_estimation> $<TARGET_OBJECTS:srsran_ch_estimation>
$<TARGET_OBJECTS:srsran_phy_common> $<TARGET_OBJECTS:srsran_phy_common>
@ -51,6 +52,7 @@ set(srsran_srcs $<TARGET_OBJECTS:srsran_agc>
$<TARGET_OBJECTS:srsran_scrambling> $<TARGET_OBJECTS:srsran_scrambling>
$<TARGET_OBJECTS:srsran_ue> $<TARGET_OBJECTS:srsran_ue>
$<TARGET_OBJECTS:srsran_enb> $<TARGET_OBJECTS:srsran_enb>
$<TARGET_OBJECTS:srsran_gnb>
) )
add_library(srsran_phy STATIC ${srsran_srcs} ) add_library(srsran_phy STATIC ${srsran_srcs} )

@ -130,7 +130,7 @@ int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t* q,
uint32_t l = m * 2; uint32_t l = m * 2;
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
@ -161,15 +161,13 @@ int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t* q,
} }
int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
const srsran_carrier_nr_t* carrier,
const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_slot_cfg_t* slot, const srsran_slot_cfg_t* slot,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,
const cf_t* slot_symbols, const cf_t* slot_symbols,
srsran_chest_ul_res_t* res) srsran_chest_ul_res_t* res)
{ {
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || res == NULL) {
res == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
} }
@ -181,7 +179,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Get group sequence // Get group sequence
uint32_t u = 0; uint32_t u = 0;
uint32_t v = 0; uint32_t v = 0;
if (srsran_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSRAN_SUCCESS) { if (srsran_pucch_nr_group_sequence(&q->carrier, cfg, &u, &v) < SRSRAN_SUCCESS) {
ERROR("Error getting group sequence"); ERROR("Error getting group sequence");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -200,11 +198,11 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
const cf_t* slot_symbols_ptr = const cf_t* slot_symbols_ptr =
&slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
SRSRAN_SUCCESS) { SRSRAN_SUCCESS) {
ERROR("Calculating alpha"); ERROR("Calculating alpha");
} }
@ -256,9 +254,9 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Compute Time Aligment error in microseconds // Compute Time Aligment error in microseconds
if (isnormal(ta_err)) { if (isnormal(ta_err)) {
ta_err /= 15e3f * (float)(1U << carrier->scs); // Convert from normalized frequency to seconds ta_err /= 15e3f * (float)(1U << q->carrier.scs); // Convert from normalized frequency to seconds
ta_err *= 1e6f; // Convert to micro-seconds ta_err *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err; res->ta_us = ta_err;
} else { } else {
res->ta_us = 0.0f; res->ta_us = 0.0f;
@ -273,7 +271,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Interpolates between DMRS symbols // Interpolates between DMRS symbols
for (uint32_t m = 0; m < n_pucch; m++) { for (uint32_t m = 0; m < n_pucch; m++) {
uint32_t l = m * 2 + 1; uint32_t l = m * 2 + 1;
cf_t* ce_ptr = &res->ce[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE]; cf_t* ce_ptr = &res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
if (m != n_pucch - 1) { if (m != n_pucch - 1) {
// If it is not the last symbol with DMRS, average between // If it is not the last symbol with DMRS, average between
@ -322,8 +320,8 @@ int srsran_dmrs_pucch_format2_put(const srsran_pucch_nr_t* q,
uint32_t l_start = resource->start_symbol_idx; uint32_t l_start = resource->start_symbol_idx;
uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols; uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols;
uint32_t k_start = SRSRAN_MIN(carrier->nof_prb - 1, resource->starting_prb) * SRSRAN_NRE + 1; uint32_t k_start = SRSRAN_MIN(q->carrier.nof_prb - 1, resource->starting_prb) * SRSRAN_NRE + 1;
uint32_t k_end = SRSRAN_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSRAN_NRE; uint32_t k_end = SRSRAN_MIN(q->carrier.nof_prb, resource->starting_prb + resource->nof_prb) * SRSRAN_NRE;
for (uint32_t l = l_start; l < l_end; l++) { for (uint32_t l = l_start; l < l_end; l++) {
// Compute sequence initial state // Compute sequence initial state
uint32_t cinit = dmrs_pucch_format2_cinit(carrier, cfg, slot, l); uint32_t cinit = dmrs_pucch_format2_cinit(carrier, cfg, slot, l);
@ -339,22 +337,20 @@ int srsran_dmrs_pucch_format2_put(const srsran_pucch_nr_t* q,
// Put sequence in k = 3 * m + 1 // Put sequence in k = 3 * m + 1
for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) { for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) {
slot_symbols[l * carrier->nof_prb * SRSRAN_NRE + k] = r_l[i]; slot_symbols[l * q->carrier.nof_prb * SRSRAN_NRE + k] = r_l[i];
} }
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q, int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
const srsran_carrier_nr_t* carrier,
const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_slot_cfg_t* slot, const srsran_slot_cfg_t* slot,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,
const cf_t* slot_symbols, const cf_t* slot_symbols,
srsran_chest_ul_res_t* res) srsran_chest_ul_res_t* res)
{ {
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || res == NULL) {
res == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
} }
@ -367,12 +363,12 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
uint32_t l_start = resource->start_symbol_idx; uint32_t l_start = resource->start_symbol_idx;
uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols; uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols;
uint32_t k_start = SRSRAN_MIN(carrier->nof_prb - 1, resource->starting_prb) * SRSRAN_NRE + 1; uint32_t k_start = SRSRAN_MIN(q->carrier.nof_prb - 1, resource->starting_prb) * SRSRAN_NRE + 1;
uint32_t k_end = SRSRAN_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSRAN_NRE; uint32_t k_end = SRSRAN_MIN(q->carrier.nof_prb, resource->starting_prb + resource->nof_prb) * SRSRAN_NRE;
uint32_t nof_ref = 4 * resource->nof_prb; uint32_t nof_ref = 4 * resource->nof_prb;
for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) { for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) {
// Compute sequence initial state // Compute sequence initial state
uint32_t cinit = dmrs_pucch_format2_cinit(carrier, cfg, slot, l); uint32_t cinit = dmrs_pucch_format2_cinit(&q->carrier, cfg, slot, l);
srsran_sequence_state_t sequence = {}; srsran_sequence_state_t sequence = {};
srsran_sequence_state_init(&sequence, cinit); srsran_sequence_state_init(&sequence, cinit);
@ -385,7 +381,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
// Put sequence in k = 3 * m + 1 // Put sequence in k = 3 * m + 1
for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) { for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) {
ce[j][i] = slot_symbols[l * carrier->nof_prb * SRSRAN_NRE + k]; ce[j][i] = slot_symbols[l * q->carrier.nof_prb * SRSRAN_NRE + k];
} }
srsran_vec_prod_conj_ccc(ce[j], r_l, ce[j], nof_ref); srsran_vec_prod_conj_ccc(ce[j], r_l, ce[j], nof_ref);
@ -418,9 +414,9 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
// Compute Time Aligment error in microseconds // Compute Time Aligment error in microseconds
if (isnormal(ta_err)) { if (isnormal(ta_err)) {
ta_err /= 15e3f * (float)(1U << carrier->scs) * 3; // Convert from normalized frequency to seconds ta_err /= 15e3f * (float)(1U << q->carrier.scs) * 3; // Convert from normalized frequency to seconds
ta_err *= 1e6f; // Convert to micro-seconds ta_err *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err; res->ta_us = ta_err;
} else { } else {
res->ta_us = 0.0f; res->ta_us = 0.0f;
@ -432,7 +428,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
// Zero order hold // Zero order hold
for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) { for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) {
for (uint32_t k = k_start - 1, i = 0; k < k_end; k++, i++) { for (uint32_t k = k_start - 1, i = 0; k < k_end; k++, i++) {
res->ce[l * carrier->nof_prb * SRSRAN_NRE + k] = ce[j][i / 3]; res->ce[l * q->carrier.nof_prb * SRSRAN_NRE + k] = ce[j][i / 3];
} }
} }

@ -0,0 +1,10 @@
#
# 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.
#
file(GLOB SOURCES "*.c")
add_library(srsran_gnb OBJECT ${SOURCES})

@ -19,10 +19,10 @@
* *
*/ */
#include "srsran/phy/enb/enb_dl_nr.h" #include "srsran/phy/gnb/gnb_dl.h"
#include <complex.h> #include <complex.h>
static int enb_dl_alloc_prb(srsran_enb_dl_nr_t* q, uint32_t new_nof_prb) static int gnb_dl_alloc_prb(srsran_gnb_dl_t* q, uint32_t new_nof_prb)
{ {
if (q->max_prb < new_nof_prb) { if (q->max_prb < new_nof_prb) {
q->max_prb = new_nof_prb; q->max_prb = new_nof_prb;
@ -43,7 +43,7 @@ static int enb_dl_alloc_prb(srsran_enb_dl_nr_t* q, uint32_t new_nof_prb)
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS], const srsran_enb_dl_nr_args_t* args) int srsran_gnb_dl_init(srsran_gnb_dl_t* q, cf_t* output[SRSRAN_MAX_PORTS], const srsran_gnb_dl_args_t* args)
{ {
if (!q || !output || !args) { if (!q || !output || !args) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
@ -60,7 +60,7 @@ int srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS],
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (enb_dl_alloc_prb(q, args->nof_max_prb) < SRSRAN_SUCCESS) { if (gnb_dl_alloc_prb(q, args->nof_max_prb) < SRSRAN_SUCCESS) {
ERROR("Error allocating"); ERROR("Error allocating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -89,7 +89,7 @@ int srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS],
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
void srsran_enb_dl_nr_free(srsran_enb_dl_nr_t* q) void srsran_gnb_dl_free(srsran_gnb_dl_t* q)
{ {
if (q == NULL) { if (q == NULL) {
return; return;
@ -108,10 +108,10 @@ void srsran_enb_dl_nr_free(srsran_enb_dl_nr_t* q)
srsran_pdcch_nr_free(&q->pdcch); srsran_pdcch_nr_free(&q->pdcch);
SRSRAN_MEM_ZERO(q, srsran_enb_dl_nr_t, 1); SRSRAN_MEM_ZERO(q, srsran_gnb_dl_t, 1);
} }
int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_t* carrier) int srsran_gnb_dl_set_carrier(srsran_gnb_dl_t* q, const srsran_carrier_nr_t* carrier)
{ {
if (srsran_pdsch_nr_set_carrier(&q->pdsch, carrier) < SRSRAN_SUCCESS) { if (srsran_pdsch_nr_set_carrier(&q->pdsch, carrier) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -122,7 +122,7 @@ int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (enb_dl_alloc_prb(q, carrier->nof_prb) < SRSRAN_SUCCESS) { if (gnb_dl_alloc_prb(q, carrier->nof_prb) < SRSRAN_SUCCESS) {
ERROR("Error allocating"); ERROR("Error allocating");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -144,9 +144,9 @@ int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_enb_dl_nr_set_pdcch_config(srsran_enb_dl_nr_t* q, int srsran_gnb_dl_set_pdcch_config(srsran_gnb_dl_t* q,
const srsran_pdcch_cfg_nr_t* cfg, const srsran_pdcch_cfg_nr_t* cfg,
const srsran_dci_cfg_nr_t* dci_cfg) const srsran_dci_cfg_nr_t* dci_cfg)
{ {
if (q == NULL || cfg == NULL) { if (q == NULL || cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
@ -165,7 +165,7 @@ int srsran_enb_dl_nr_set_pdcch_config(srsran_enb_dl_nr_t* q,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
void srsran_enb_dl_nr_gen_signal(srsran_enb_dl_nr_t* q) void srsran_gnb_dl_gen_signal(srsran_gnb_dl_t* q)
{ {
if (q == NULL) { if (q == NULL) {
return; return;
@ -176,7 +176,7 @@ void srsran_enb_dl_nr_gen_signal(srsran_enb_dl_nr_t* q)
} }
} }
int srsran_enb_dl_nr_base_zero(srsran_enb_dl_nr_t* q) int srsran_gnb_dl_base_zero(srsran_gnb_dl_t* q)
{ {
if (q == NULL) { if (q == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
@ -190,7 +190,7 @@ int srsran_enb_dl_nr_base_zero(srsran_enb_dl_nr_t* q)
} }
static int static int
enb_dl_nr_pdcch_put_msg(srsran_enb_dl_nr_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_msg_nr_t* dci_msg) gnb_dl_pdcch_put_msg(srsran_gnb_dl_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_msg_nr_t* dci_msg)
{ {
if (dci_msg->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET || if (dci_msg->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET ||
!q->pdcch_cfg.coreset_present[dci_msg->ctx.coreset_id]) { !q->pdcch_cfg.coreset_present[dci_msg->ctx.coreset_id]) {
@ -222,9 +222,7 @@ enb_dl_nr_pdcch_put_msg(srsran_enb_dl_nr_t* q, const srsran_slot_cfg_t* slot_cfg
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_enb_dl_nr_pdcch_put_dl(srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdcch_put_dl(srsran_gnb_dl_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_dl_nr_t* dci_dl)
const srsran_slot_cfg_t* slot_cfg,
const srsran_dci_dl_nr_t* dci_dl)
{ {
if (q == NULL || slot_cfg == NULL || dci_dl == NULL) { if (q == NULL || slot_cfg == NULL || dci_dl == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
@ -239,12 +237,10 @@ int srsran_enb_dl_nr_pdcch_put_dl(srsran_enb_dl_nr_t* q,
INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce); INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce);
return enb_dl_nr_pdcch_put_msg(q, slot_cfg, &dci_msg); return gnb_dl_pdcch_put_msg(q, slot_cfg, &dci_msg);
} }
int srsran_enb_dl_nr_pdcch_put_ul(srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdcch_put_ul(srsran_gnb_dl_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_ul_nr_t* dci_ul)
const srsran_slot_cfg_t* slot_cfg,
const srsran_dci_ul_nr_t* dci_ul)
{ {
if (q == NULL || slot_cfg == NULL || dci_ul == NULL) { if (q == NULL || slot_cfg == NULL || dci_ul == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
@ -259,13 +255,13 @@ int srsran_enb_dl_nr_pdcch_put_ul(srsran_enb_dl_nr_t* q,
INFO("DCI DL NR: L=%d; ncce=%d;", dci_ul->ctx.location.L, dci_ul->ctx.location.ncce); INFO("DCI DL NR: L=%d; ncce=%d;", dci_ul->ctx.location.L, dci_ul->ctx.location.ncce);
return enb_dl_nr_pdcch_put_msg(q, slot_cfg, &dci_msg); return gnb_dl_pdcch_put_msg(q, slot_cfg, &dci_msg);
} }
int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdsch_put(srsran_gnb_dl_t* q,
const srsran_slot_cfg_t* slot, const srsran_slot_cfg_t* slot,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
uint8_t* data[SRSRAN_MAX_TB]) uint8_t* data[SRSRAN_MAX_TB])
{ {
if (srsran_dmrs_sch_put_sf(&q->dmrs, slot, cfg, &cfg->grant, q->sf_symbols[0]) < SRSRAN_SUCCESS) { if (srsran_dmrs_sch_put_sf(&q->dmrs, slot, cfg, &cfg->grant, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -278,10 +274,7 @@ int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_enb_dl_nr_pdsch_info(const srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdsch_info(const srsran_gnb_dl_t* q, const srsran_sch_cfg_nr_t* cfg, char* str, uint32_t str_len)
const srsran_sch_cfg_nr_t* cfg,
char* str,
uint32_t str_len)
{ {
int len = 0; int len = 0;
@ -291,10 +284,7 @@ int srsran_enb_dl_nr_pdsch_info(const srsran_enb_dl_nr_t* q,
return len; return len;
} }
int srsran_enb_dl_nr_pdcch_dl_info(const srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdcch_dl_info(const srsran_gnb_dl_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
const srsran_dci_dl_nr_t* dci,
char* str,
uint32_t str_len)
{ {
int len = 0; int len = 0;
@ -304,10 +294,7 @@ int srsran_enb_dl_nr_pdcch_dl_info(const srsran_enb_dl_nr_t* q,
return len; return len;
} }
int srsran_enb_dl_nr_pdcch_ul_info(const srsran_enb_dl_nr_t* q, int srsran_gnb_dl_pdcch_ul_info(const srsran_gnb_dl_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
const srsran_dci_ul_nr_t* dci,
char* str,
uint32_t str_len)
{ {
int len = 0; int len = 0;

@ -0,0 +1,310 @@
/**
*
* \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 "srsran/phy/gnb/gnb_ul.h"
#include "srsran/phy/ch_estimation/dmrs_pucch.h"
/**
* @brief Shifts FFT window a fraction of the cyclic prefix. Set to 0.0f for disabling.
* @note Increases protection against inter-symbol interference in case of synchronization error in expense of computing
* performance
*/
#define GNB_UL_NR_FFT_WINDOW_OFFSET 0.5f
static int gnb_ul_alloc_prb(srsran_gnb_ul_t* q, uint32_t new_nof_prb)
{
if (q->max_prb < new_nof_prb) {
q->max_prb = new_nof_prb;
srsran_chest_dl_res_free(&q->chest_pusch);
if (srsran_chest_dl_res_init(&q->chest_pusch, q->max_prb) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
srsran_chest_ul_res_free(&q->chest_pucch);
if (srsran_chest_ul_res_init(&q->chest_pucch, q->max_prb) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (q->sf_symbols[0] != NULL) {
free(q->sf_symbols[0]);
}
q->sf_symbols[0] = srsran_vec_cf_malloc(SRSRAN_SLOT_LEN_RE_NR(q->max_prb));
if (q->sf_symbols[0] == NULL) {
ERROR("Malloc");
return SRSRAN_ERROR;
}
}
return SRSRAN_SUCCESS;
}
int srsran_gnb_ul_init(srsran_gnb_ul_t* q, cf_t* input, const srsran_gnb_ul_args_t* args)
{
if (q == NULL || args == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (gnb_ul_alloc_prb(q, args->nof_max_prb) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_pusch_nr_init_gnb(&q->pusch, &args->pusch) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_pucch_nr_init(&q->pucch, &args->pucch) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_dmrs_sch_init(&q->dmrs, true) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
srsran_ofdm_cfg_t ofdm_cfg = {};
ofdm_cfg.nof_prb = args->nof_max_prb;
ofdm_cfg.in_buffer = input;
ofdm_cfg.out_buffer = q->sf_symbols[0];
ofdm_cfg.rx_window_offset = GNB_UL_NR_FFT_WINDOW_OFFSET;
ofdm_cfg.symbol_sz = srsran_min_symbol_sz_rb(args->nof_max_prb);
ofdm_cfg.keep_dc = true;
if (srsran_ofdm_rx_init_cfg(&q->fft, &ofdm_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
void srsran_gnb_ul_free(srsran_gnb_ul_t* q)
{
if (q == NULL) {
return;
}
srsran_ofdm_tx_free(&q->fft);
srsran_pusch_nr_free(&q->pusch);
srsran_pucch_nr_free(&q->pucch);
srsran_dmrs_sch_free(&q->dmrs);
srsran_chest_dl_res_free(&q->chest_pusch);
srsran_chest_ul_res_free(&q->chest_pucch);
if (q->sf_symbols[0] != NULL) {
free(q->sf_symbols[0]);
}
SRSRAN_MEM_ZERO(q, srsran_gnb_ul_t, 1);
}
int srsran_gnb_ul_set_carrier(srsran_gnb_ul_t* q, const srsran_carrier_nr_t* carrier)
{
if (q == NULL || carrier == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
q->carrier = *carrier;
if (gnb_ul_alloc_prb(q, carrier->nof_prb) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_pusch_nr_set_carrier(&q->pusch, carrier) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_pucch_nr_set_carrier(&q->pucch, carrier) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_dmrs_sch_set_carrier(&q->dmrs, carrier) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
srsran_ofdm_cfg_t ofdm_cfg = {};
ofdm_cfg.nof_prb = carrier->nof_prb;
ofdm_cfg.rx_window_offset = GNB_UL_NR_FFT_WINDOW_OFFSET;
ofdm_cfg.symbol_sz = srsran_min_symbol_sz_rb(carrier->nof_prb);
ofdm_cfg.keep_dc = true;
if (srsran_ofdm_rx_init_cfg(&q->fft, &ofdm_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int srsran_gnb_ul_fft(srsran_gnb_ul_t* q)
{
if (q == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
srsran_ofdm_rx_sf(&q->fft);
return SRSRAN_SUCCESS;
}
int srsran_gnb_ul_get_pusch(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
srsran_pusch_res_nr_t* data)
{
if (q == NULL || cfg == NULL || grant == NULL || data == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (srsran_dmrs_sch_estimate(&q->dmrs, slot_cfg, cfg, grant, q->sf_symbols[0], &q->chest_pusch) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_pusch_nr_decode(&q->pusch, cfg, grant, &q->chest_pusch, q->sf_symbols, data) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int gnb_ul_decode_pucch_format1(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_uci_value_nr_t* uci_value)
{
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
// Set ACK bits
uint32_t nof_bits = SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_cfg->ack.count);
// Set SR bits
// For a positive SR transmission using PUCCH format 1, the UE transmits the PUCCH as described in [4, TS
// 38.211] by setting b ( 0 ) = 0 .
if (nof_bits == 0 && uci_cfg->o_sr > 0) {
nof_bits = 1;
}
// Channel estimation
if (srsran_dmrs_pucch_format1_estimate(&q->pucch, cfg, slot_cfg, resource, q->sf_symbols[0], &q->chest_pucch) <
SRSRAN_SUCCESS) {
ERROR("Error in PUCCH format 1 estimation");
return SRSRAN_ERROR;
}
// Actual decode
float norm_corr = 0.0f;
if (srsran_pucch_nr_format1_decode(
&q->pucch, cfg, slot_cfg, resource, &q->chest_pucch, q->sf_symbols[0], b, nof_bits, &norm_corr) <
SRSRAN_SUCCESS) {
ERROR("Error in PUCCH format 1 decoding");
return SRSRAN_ERROR;
}
// Take valid decision
uci_value->valid = (norm_corr > 0.5f);
// De-multiplex ACK bits
for (uint32_t i = 0; i < nof_bits; i++) {
uci_value->ack[i] = b[i];
}
return SRSRAN_SUCCESS;
}
static int gnb_ul_decode_pucch_format2(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_uci_value_nr_t* uci_value)
{
if (srsran_dmrs_pucch_format2_estimate(&q->pucch, cfg, slot_cfg, resource, q->sf_symbols[0], &q->chest_pucch) <
SRSRAN_SUCCESS) {
ERROR("Error in PUCCH format 2 estimation");
return SRSRAN_ERROR;
}
if (srsran_pucch_nr_format_2_3_4_decode(
&q->pucch, cfg, slot_cfg, resource, uci_cfg, &q->chest_pucch, q->sf_symbols[0], uci_value) < SRSRAN_SUCCESS) {
ERROR("Error in PUCCH format 2 decoding");
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_pucch_nr_common_cfg_t* cfg,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_uci_value_nr_t* uci_value)
{
if (q == NULL || slot_cfg == NULL || cfg == NULL || resource == NULL || uci_cfg == NULL || uci_value == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Estimate channel
switch (resource->format) {
case SRSRAN_PUCCH_NR_FORMAT_1:
return gnb_ul_decode_pucch_format1(q, slot_cfg, cfg, resource, uci_cfg, uci_value);
case SRSRAN_PUCCH_NR_FORMAT_2:
return gnb_ul_decode_pucch_format2(q, slot_cfg, cfg, resource, uci_cfg, uci_value);
case SRSRAN_PUCCH_NR_FORMAT_0:
case SRSRAN_PUCCH_NR_FORMAT_3:
case SRSRAN_PUCCH_NR_FORMAT_4:
case SRSRAN_PUCCH_NR_FORMAT_ERROR:
ERROR("Invalid or not implemented PUCCH-NR format %d", (int)resource->format);
}
return SRSRAN_ERROR;
}
uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data,
char* str,
uint32_t str_len)
{
if (q == NULL || uci_data == NULL) {
return 0;
}
uint32_t len = 0;
len += srsran_pucch_nr_info(resource, uci_data, str, str_len - len);
len = srsran_print_check(
str, str_len, len, "snr=%+.1f valid=%c", q->chest_pucch.snr_db, uci_data->value.valid ? 'y' : 'n');
return len;
}
uint32_t srsran_gnb_ul_pusch_info(srsran_gnb_ul_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
{
if (q == NULL || cfg == NULL || res == NULL) {
return 0;
}
uint32_t len = 0;
len += srsran_pusch_nr_rx_info(&q->pusch, cfg, &cfg->grant, res, str, str_len - len);
len = srsran_print_check(str, str_len, len, "snr=%+.1f", q->chest_pusch.snr_db);
return len;
}

@ -0,0 +1,346 @@
/**
*
* \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 "srsran/phy/phch/harq_ack.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
// Implements TS 38.213 Table 9.1.3-1: Value of counter DAI in DCI format 1_0 and of counter DAI or total DAI DCI format
// 1_1
static uint32_t ue_dl_nr_V_DL_DAI(uint32_t dai)
{
return dai + 1;
}
static int harq_ack_gen_ack_type2(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_cfg_nr_t* uci_cfg)
{
bool harq_ack_spatial_bundling =
ack_info->use_pusch ? cfg->harq_ack_spatial_bundling_pusch : cfg->harq_ack_spatial_bundling_pucch;
uint32_t m = 0; // PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion index: lower index corresponds to
// earlier PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion
uint32_t j = 0;
uint32_t V_temp = 0;
uint32_t V_temp2 = 0;
uint32_t N_DL_cells = ack_info->nof_cc; // number of serving cells configured by higher layers for the UE
// Initialise ACK bits
SRSRAN_MEM_ZERO(uci_cfg->ack.bits, srsran_harq_ack_bit_t, SRSRAN_HARQ_ACK_MAX_NOF_BITS);
// The following code follows the exact pseudo-code provided in TS 38.213 9.1.3.1 Type-2 HARQ-ACK codebook ...
while (m < SRSRAN_UCI_NR_MAX_M) {
uint32_t c = 0; // serving cell index: lower indexes correspond to lower RRC indexes of corresponding cell
while (c < N_DL_cells) {
// Get ACK information of serving cell c for the PDCH monitoring occasion m
const srsran_harq_ack_m_t* ack = &ack_info->cc[c].m[m];
// Get DAI counter value
uint32_t V_DL_CDAI = ue_dl_nr_V_DL_DAI(ack->resource.v_dai_dl);
uint32_t V_DL_TDAI = ack->resource.dci_format_1_1 ? ue_dl_nr_V_DL_DAI(ack->resource.v_dai_dl) : UINT32_MAX;
// Get ACK values
srsran_harq_ack_bit_t ack_tb0 = {};
ack_tb0.tb0 = true;
ack_tb0.cc_idx = c;
ack_tb0.m_idx = m;
ack_tb0.pid = ack->resource.pid;
srsran_harq_ack_bit_t ack_tb1 = {};
ack_tb1.tb1 = true;
ack_tb1.cc_idx = c;
ack_tb1.m_idx = m;
ack_tb1.pid = ack->resource.pid;
// For a PDCCH monitoring occasion with DCI format 1_0 or DCI format 1_1 in the active DL BWP of a serving cell,
// when a UE receives a PDSCH with one transport block and the value of maxNrofCodeWordsScheduledByDCI is 2, the
// HARQ-ACK information is associated with the first transport block and the UE generates a NACK for the second
// transport block if harq-ACK-SpatialBundlingPUCCH is not provided and generates HARQ-ACK information with
// value of ACK for the second transport block if harq-ACK-SpatialBundlingPUCCH is provided.
if (cfg->max_cw_sched_dci_is_2 && !ack->second_tb_present) {
ack_tb1.tb1 = false;
}
// if PDCCH monitoring occasion m is before an active DL BWP change on serving cell c or an active UL
// BWP change on the PCell and an active DL BWP change is not triggered by a DCI format 1_1 in PDCCH
// monitoring occasion m
if (ack->dl_bwp_changed || ack->ul_bwp_changed) {
c = c + 1;
} else {
if (ack->present) {
// Load ACK resource data into UCI info
uci_cfg->pucch.resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id;
uci_cfg->pucch.rnti = ack_info->cc[c].m[m].resource.rnti;
if (V_DL_CDAI <= V_temp) {
j = j + 1;
}
V_temp = V_DL_CDAI;
if (V_DL_TDAI == UINT32_MAX) {
V_temp2 = V_DL_CDAI;
} else {
V_temp2 = V_DL_TDAI;
}
// if harq-ACK-SpatialBundlingPUCCH is not provided and m is a monitoring occasion for PDCCH with DCI format
// 1_0 or DCI format 1_1 and the UE is configured by maxNrofCodeWordsScheduledByDCI with reception of two
// transport blocks for at least one configured DL BWP of at least one serving cell,
if (!harq_ack_spatial_bundling && cfg->max_cw_sched_dci_is_2) {
uci_cfg->ack.bits[8 * j + 2 * (V_DL_CDAI - 1) + 0] = ack_tb0;
uci_cfg->ack.bits[8 * j + 2 * (V_DL_CDAI - 1) + 1] = ack_tb1;
}
// elseif harq-ACK-SpatialBundlingPUCCH is provided to the UE and m is a monitoring occasion for
// PDCCH with DCI format 1_1 and the UE is configured by maxNrofCodeWordsScheduledByDCI with
// reception of two transport blocks in at least one configured DL BWP of a serving cell,
else if (harq_ack_spatial_bundling && ack->resource.dci_format_1_1 && cfg->max_cw_sched_dci_is_2) {
ack_tb0.tb1 = true;
uci_cfg->ack.bits[4 * j + (V_DL_CDAI - 1)] = ack_tb0;
}
// else
else {
uci_cfg->ack.bits[4 * j + (V_DL_CDAI - 1)] = ack_tb0;
}
}
c = c + 1;
}
}
m = m + 1;
}
if (V_temp2 < V_temp) {
j = j + 1;
}
// if harq-ACK-SpatialBundlingPUCCH is not provided to the UE and the UE is configured by
// maxNrofCodeWordsScheduledByDCI with reception of two transport blocks for at least one configured DL BWP of a
// serving cell,
if (!harq_ack_spatial_bundling && cfg->max_cw_sched_dci_is_2) {
uci_cfg->ack.count = 2 * (4 * j + V_temp2);
} else {
uci_cfg->ack.count = 4 * j + V_temp2;
}
// Implement here SPS PDSCH reception
// ...
return SRSRAN_SUCCESS;
}
static int harq_ack_k1(const srsran_harq_ack_cfg_hl_t* cfg, const srsran_dci_dl_nr_t* dci_dl)
{
// For DCI format 1_0, the PDSCH-to-HARQ_feedback timing indicator field values map to {1, 2, 3, 4, 5, 6, 7, 8}
if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) {
return (int)dci_dl->harq_feedback + 1;
}
// For DCI format 1_1, if present, the PDSCH-to-HARQ_feedback timing indicator field values map to values for a set of
// number of slots provided by dl-DataToUL-ACK as defined in Table 9.2.3-1.
if (dci_dl->harq_feedback >= SRSRAN_MAX_NOF_DL_DATA_TO_UL || dci_dl->harq_feedback >= cfg->nof_dl_data_to_ul_ack) {
ERROR("Out-of-range PDSCH-to-HARQ feedback index (%d, max %d)", dci_dl->harq_feedback, cfg->nof_dl_data_to_ul_ack);
return SRSRAN_ERROR;
}
return (int)cfg->dl_data_to_ul_ack[dci_dl->harq_feedback];
}
int srsran_harq_ack_resource(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_harq_ack_resource_t* pdsch_ack_resource)
{
if (cfg == NULL || dci_dl == NULL || pdsch_ack_resource == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Calculate Data to UL ACK timing k1
int k1 = harq_ack_k1(cfg, dci_dl);
if (k1 < SRSRAN_ERROR) {
ERROR("Error calculating K1");
return SRSRAN_ERROR;
}
// Fill PDSCH resource
pdsch_ack_resource->dci_format_1_1 = (dci_dl->ctx.format == srsran_dci_format_nr_1_1);
pdsch_ack_resource->k1 = k1;
pdsch_ack_resource->v_dai_dl = dci_dl->dai;
pdsch_ack_resource->rnti = dci_dl->ctx.rnti;
pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource;
pdsch_ack_resource->pid = dci_dl->pid;
return SRSRAN_SUCCESS;
}
int srsran_harq_ack_gen_uci_cfg(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_cfg_nr_t* uci_cfg)
{
// Check inputs
if (cfg == NULL || ack_info == NULL || uci_cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// According TS 38.213 9.1.2 Type-1 HARQ-ACK codebook determination
if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_semi_static) {
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = semi-static.
ERROR("Type-1 HARQ-ACK codebook determination is NOT implemented");
return SRSRAN_ERROR;
}
// According TS 38.213 9.1.3 Type-2 HARQ-ACK codebook determination
if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic) {
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = dynamic.
return harq_ack_gen_ack_type2(cfg, ack_info, uci_cfg);
}
ERROR("No HARQ-ACK codebook determination is NOT implemented");
return SRSRAN_ERROR;
}
int srsran_harq_ack_pack(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data)
{
// Check inputs
if (cfg == NULL || ack_info == NULL || uci_data == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Generate configuration
if (srsran_harq_ack_gen_uci_cfg(cfg, ack_info, &uci_data->cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
// Actual packing
for (uint32_t i = 0; i < uci_data->cfg.ack.count; i++) {
srsran_harq_ack_bit_t* ack_bit = &uci_data->cfg.ack.bits[i];
// Skip bit if no TB is used
if (!ack_bit->tb0 && !ack_bit->tb1) {
uci_data->value.ack[i] = 0;
continue;
}
// Only TB0
if (ack_bit->tb0 && !ack_bit->tb1) {
uci_data->value.ack[i] = ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[0];
continue;
}
// Only TB1
if (!ack_bit->tb0 && ack_bit->tb1) {
uci_data->value.ack[i] = ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[1];
continue;
}
// Both TB with bundling
uci_data->value.ack[i] = ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[0];
uci_data->value.ack[i] &= ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[1];
}
return SRSRAN_SUCCESS;
}
int srsran_harq_ack_unpack(const srsran_harq_ack_cfg_hl_t* cfg,
const srsran_uci_data_nr_t* uci_data,
srsran_pdsch_ack_nr_t* ack_info)
{
// Check inputs
if (cfg == NULL || ack_info == NULL || uci_data == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Actual packing
for (uint32_t i = 0; i < uci_data->cfg.ack.count; i++) {
const srsran_harq_ack_bit_t* ack_bit = &uci_data->cfg.ack.bits[i];
// Extract TB0
if (ack_bit->tb0) {
ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[0] = uci_data->value.ack[i];
}
// Extract TB1
if (ack_bit->tb1) {
ack_info->cc[ack_bit->cc_idx].m[ack_bit->m_idx].value[1] = uci_data->value.ack[i];
}
}
return SRSRAN_SUCCESS;
}
int srsran_harq_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, const srsran_harq_ack_m_t* m)
{
// Check inputs
if (ack_info == NULL || m == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Protect SCell index and extract information
if (m->resource.scell_idx >= SRSRAN_MAX_CARRIERS) {
ERROR("Serving cell index (%d) exceeds maximum", m->resource.scell_idx);
return SRSRAN_ERROR;
}
srsran_harq_ack_cc_t* cc = &ack_info->cc[m->resource.scell_idx];
// Find insertion index
uint32_t idx = cc->M; // Append at the end by default
for (uint32_t i = 0; i < cc->M; i++) {
if (cc->m[i].resource.k1 < m->resource.k1) {
idx = i;
break;
}
}
// Increment count
cc->M += 1;
// Make space for insertion
for (uint32_t i = cc->M - 1; i > idx; i--) {
cc->m[i] = cc->m[i - 1];
}
// Actual insertion
cc->m[idx] = *m;
return SRSRAN_SUCCESS;
}
uint32_t srsran_harq_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len)
{
uint32_t len = 0;
if (ack_info == NULL || str == NULL) {
return 0;
}
// Print base info
len = srsran_print_check(
str, str_len, len, "use_pusch=%c nof_cc=%d\n", ack_info->use_pusch ? 'y' : 'n', ack_info->nof_cc);
// Iterate all carriers
for (uint32_t cc = 0; cc < ack_info->nof_cc; cc++) {
len = srsran_print_check(str, str_len, len, " CC %d: M=%d\n", cc, ack_info->cc[cc].M);
for (uint32_t m = 0; m < ack_info->cc[cc].M; m++) {
if (ack_info->cc[cc].m[m].present) {
len = srsran_print_check(str,
str_len,
len,
" m %d: k1=%d dai=%d ack=%d\n",
m,
ack_info->cc[cc].m[m].resource.k1,
ack_info->cc[cc].m[m].resource.v_dai_dl,
ack_info->cc[cc].m[m].value[0]);
}
}
}
return len;
}

@ -238,7 +238,7 @@ static uint32_t phch_cfg_uci_to_str(const srsran_uci_cfg_nr_t* uci, char* str, u
len = srsran_print_check(str, str_len, len, " beta_csi_part1_offset=%.2f\n", uci->pusch.beta_csi1_offset); len = srsran_print_check(str, str_len, len, " beta_csi_part1_offset=%.2f\n", uci->pusch.beta_csi1_offset);
len = srsran_print_check(str, str_len, len, " beta_csi_part2_offset=%.2f\n", uci->pusch.beta_csi1_offset); len = srsran_print_check(str, str_len, len, " beta_csi_part2_offset=%.2f\n", uci->pusch.beta_csi1_offset);
len = srsran_print_check(str, str_len, len, " o_csi1=%d\n", srsran_csi_part1_nof_bits(uci->csi, uci->nof_csi)); len = srsran_print_check(str, str_len, len, " o_csi1=%d\n", srsran_csi_part1_nof_bits(uci->csi, uci->nof_csi));
len = srsran_print_check(str, str_len, len, " o_ack=%d\n", uci->o_ack); len = srsran_print_check(str, str_len, len, " o_ack=%d\n", uci->ack.count);
return len; return len;
} }

@ -461,7 +461,8 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
srsran_chest_ul_res_t* chest_res, srsran_chest_ul_res_t* chest_res,
cf_t* slot_symbols, cf_t* slot_symbols,
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS], uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS],
uint32_t nof_bits) uint32_t nof_bits,
float* norm_corr)
{ {
uint32_t m_cs = 0; uint32_t m_cs = 0;
@ -533,8 +534,14 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1); srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1);
// Hard decision // Hard decision
float corr = 0.0f;
for (uint32_t i = 0; i < nof_bits; i++) { for (uint32_t i = 0; i < nof_bits; i++) {
b[i] = llr[i] > 0.0f ? 1 : 0; b[i] = llr[i] > 0.0f ? 1 : 0;
corr += fabsf(llr[i]);
}
if (norm_corr != NULL && nof_bits > 0) {
*norm_corr = corr / nof_bits;
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -771,10 +778,10 @@ static uint32_t pucch_nr_resource_info(const srsran_pucch_nr_resource_t* r, char
return len; return len;
} }
uint32_t srsran_pucch_nr_tx_info(const srsran_pucch_nr_resource_t* resource, uint32_t srsran_pucch_nr_info(const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data, const srsran_uci_data_nr_t* uci_data,
char* str, char* str,
uint32_t str_len) uint32_t str_len)
{ {
uint32_t len = 0; uint32_t len = 0;

@ -383,7 +383,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
// if the number of HARQ-ACK information bits to be transmitted on PUSCH is 0, 1 or 2 bits // if the number of HARQ-ACK information bits to be transmitted on PUSCH is 0, 1 or 2 bits
uint32_t G_ack_rvd = 0; uint32_t G_ack_rvd = 0;
if (cfg->o_ack <= 2) { if (cfg->ack.count <= 2) {
// the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause // the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause
// 6.3.2.4.2.1, by setting O_ACK = 2 ; // 6.3.2.4.2.1, by setting O_ACK = 2 ;
G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&cfg->pusch, 2); G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&cfg->pusch, 2);
@ -421,7 +421,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
uint32_t ack_d = 0; uint32_t ack_d = 0;
uint32_t ack_m_re_count = 0; uint32_t ack_m_re_count = 0;
if (l >= l1) { if (l >= l1) {
if (cfg->o_ack <= 2 && m_ack_count < G_ack_rvd) { if (cfg->ack.count <= 2 && m_ack_count < G_ack_rvd) {
ack_d = 1; ack_d = 1;
ack_m_re_count = M_ulsch_sc; ack_m_re_count = M_ulsch_sc;
if (G_ack_rvd - m_ack_count < M_uci_sc * Nl * Qm) { if (G_ack_rvd - m_ack_count < M_uci_sc * Nl * Qm) {
@ -507,7 +507,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
// Set reserved bits only if there are ACK bits // Set reserved bits only if there are ACK bits
if (reserved) { if (reserved) {
if (cfg->o_ack > 0) { if (cfg->ack.count > 0) {
for (uint32_t j = 0; j < Nl * Qm; j++) { for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_ack[m_ack_count++] = m_all_count + j; pos_ack[m_ack_count++] = m_all_count + j;
} }
@ -540,7 +540,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
q->G_ulsch = m_ulsch_count; q->G_ulsch = m_ulsch_count;
// Assert Number of bits // Assert Number of bits
if (G_ack_rvd != 0 && G_ack_rvd != m_ack_count && cfg->o_ack > 0) { if (G_ack_rvd != 0 && G_ack_rvd != m_ack_count && cfg->ack.count > 0) {
ERROR("Not matched %d!=%d", G_ack_rvd, m_ack_count); ERROR("Not matched %d!=%d", G_ack_rvd, m_ack_count);
} }
if (G_ack != 0 && G_ack != m_ack_count) { if (G_ack != 0 && G_ack != m_ack_count) {
@ -560,7 +560,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
DEBUG("UL-SCH bit positions:"); DEBUG("UL-SCH bit positions:");
srsran_vec_fprint_i(stdout, (int*)pos_ulsch, m_ulsch_count); srsran_vec_fprint_i(stdout, (int*)pos_ulsch, m_ulsch_count);
} }
if (m_ack_count != 0 && cfg->o_ack > 0) { if (m_ack_count != 0 && cfg->ack.count > 0) {
DEBUG("HARQ-ACK bit positions [%d]:", m_ack_count); DEBUG("HARQ-ACK bit positions [%d]:", m_ack_count);
srsran_vec_fprint_i(stdout, (int*)pos_ack, m_ack_count); srsran_vec_fprint_i(stdout, (int*)pos_ack, m_ack_count);
} }
@ -671,7 +671,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
srsran_sequence_apply_bit(b, q->b[tb->cw_idx], nof_bits, cinit); srsran_sequence_apply_bit(b, q->b[tb->cw_idx], nof_bits, cinit);
// Special Scrambling condition // Special Scrambling condition
if (cfg->uci.o_ack <= 2) { if (cfg->uci.ack.count <= 2) {
for (uint32_t i = 0; i < q->G_ack; i++) { for (uint32_t i = 0; i < q->G_ack; i++) {
uint32_t idx = q->pos_ack[i]; uint32_t idx = q->pos_ack[i];
if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) { if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) {
@ -802,7 +802,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod); uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod);
// Calculate HARQ-ACK bits // Calculate HARQ-ACK bits
int n = srsran_uci_nr_pusch_ack_nof_bits(&cfg->uci.pusch, cfg->uci.o_ack); int n = srsran_uci_nr_pusch_ack_nof_bits(&cfg->uci.pusch, cfg->uci.ack.count);
if (n < SRSRAN_SUCCESS) { if (n < SRSRAN_SUCCESS) {
ERROR("Calculating G_ack"); ERROR("Calculating G_ack");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -918,7 +918,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
srsran_chest_dl_res_t* channel, srsran_chest_dl_res_t* channel,
cf_t* sf_symbols[SRSRAN_MAX_PORTS], cf_t* sf_symbols[SRSRAN_MAX_PORTS],
srsran_pusch_res_nr_t* data[SRSRAN_MAX_TB]) srsran_pusch_res_nr_t* data)
{ {
// Check input pointers // Check input pointers
if (!q || !cfg || !grant || !data || !sf_symbols || !channel) { if (!q || !cfg || !grant || !data || !sf_symbols || !channel) {
@ -987,7 +987,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
// SCH decode // SCH decode
for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) {
if (pusch_nr_decode_codeword(q, cfg, &grant->tb[tb], data[0], grant->rnti) < SRSRAN_SUCCESS) { if (pusch_nr_decode_codeword(q, cfg, &grant->tb[tb], data, grant->rnti) < SRSRAN_SUCCESS) {
ERROR("Error encoding TB %d", tb); ERROR("Error encoding TB %d", tb);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }

@ -286,7 +286,7 @@ int srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data(const srsran_sch_hl_cfg_nr_
ERROR("Unhandled case (%d, %d)", cfg->dmrs_type, cfg->dmrs_max_length); ERROR("Unhandled case (%d, %d)", cfg->dmrs_type, cfg->dmrs_max_length);
return SRSRAN_ERROR; return SRSRAN_ERROR;
default: default:
ERROR("Invalid UL DCI format %s", srsran_dci_format_nr_string(dci->ctx.format)); ERROR("Invalid DL DCI format %s", srsran_dci_format_nr_string(dci->ctx.format));
} }
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -530,6 +530,12 @@ int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
tb->nof_bits = tb->nof_re * Qm; tb->nof_bits = tb->nof_re * Qm;
tb->enabled = true; tb->enabled = true;
// Calculate actual rate
tb->R_prime = 0.0;
if (tb->nof_re != 0) {
tb->R_prime = (double)tb->tbs / (double)tb->nof_bits;
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -764,6 +770,7 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_dci_ul_nr_t*
} }
int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
const srsran_slot_cfg_t* slot_cfg,
const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
const srsran_dci_ul_nr_t* dci_ul, const srsran_dci_ul_nr_t* dci_ul,
srsran_sch_cfg_nr_t* pusch_cfg, srsran_sch_cfg_nr_t* pusch_cfg,
@ -826,9 +833,9 @@ static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_
// Select Beta Offset index from the number of HARQ-ACK bits // Select Beta Offset index from the number of HARQ-ACK bits
uint32_t beta_offset_index = beta_offsets->ack_index1; uint32_t beta_offset_index = beta_offsets->ack_index1;
if (uci_cfg->o_ack > 11) { if (uci_cfg->ack.count > 11) {
beta_offset_index = beta_offsets->ack_index3; beta_offset_index = beta_offsets->ack_index3;
} else if (uci_cfg->o_ack > 2) { } else if (uci_cfg->ack.count > 2) {
beta_offset_index = beta_offsets->ack_index2; beta_offset_index = beta_offsets->ack_index2;
} }
@ -836,7 +843,7 @@ static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_
if (beta_offset_index >= RA_NR_BETA_OFFSET_HARQACK_SIZE) { if (beta_offset_index >= RA_NR_BETA_OFFSET_HARQACK_SIZE) {
ERROR("Beta offset index for HARQ-ACK (%d) for O_ack=%d exceeds table size (%d)", ERROR("Beta offset index for HARQ-ACK (%d) for O_ack=%d exceeds table size (%d)",
beta_offset_index, beta_offset_index,
uci_cfg->o_ack, uci_cfg->ack.count,
RA_NR_BETA_OFFSET_HARQACK_SIZE); RA_NR_BETA_OFFSET_HARQACK_SIZE);
return NAN; return NAN;
} }
@ -1024,8 +1031,8 @@ int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier,
// Calculate number of UCI encoded bits // Calculate number of UCI encoded bits
int Gack = 0; int Gack = 0;
if (pusch_cfg->uci.o_ack > 2) { if (pusch_cfg->uci.ack.count > 2) {
Gack = srsran_uci_nr_pusch_ack_nof_bits(&pusch_cfg->uci.pusch, pusch_cfg->uci.o_ack); Gack = srsran_uci_nr_pusch_ack_nof_bits(&pusch_cfg->uci.pusch, pusch_cfg->uci.ack.count);
if (Gack < SRSRAN_SUCCESS) { if (Gack < SRSRAN_SUCCESS) {
ERROR("Error calculating Qdack"); ERROR("Error calculating Qdack");
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -429,7 +429,7 @@ int srsran_ra_ul_nr_pucch_format_2_3_min_prb(const srsran_pucch_nr_resource_t* r
} }
// Compute total number of UCI bits // Compute total number of UCI bits
uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); uint32_t O_total = uci_cfg->ack.count + uci_cfg->o_sr + srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
// Add CRC bits if any // Add CRC bits if any
O_total += srsran_uci_nr_crc_len(O_total); O_total += srsran_uci_nr_crc_len(O_total);
@ -539,7 +539,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
// - At least one positive SR // - At least one positive SR
// - up to 2 HARQ-ACK // - up to 2 HARQ-ACK
// - No CSI report // - No CSI report
if (uci_cfg->pucch.sr_positive_present > 0 && uci_cfg->o_ack <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && if (uci_cfg->pucch.sr_positive_present > 0 && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
uci_cfg->nof_csi == 0) { uci_cfg->nof_csi == 0) {
uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id; uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) { if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) {
@ -563,7 +563,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
// - Irrelevant SR opportunities // - Irrelevant SR opportunities
// - More than 2 HARQ-ACK // - More than 2 HARQ-ACK
// - No CSI report // - No CSI report
if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { if (uci_cfg->o_sr > 0 && uci_cfg->ack.count > SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) {
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource); return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource);
} }
@ -571,7 +571,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
// - Irrelevant SR opportunities // - Irrelevant SR opportunities
// - No HARQ-ACK // - No HARQ-ACK
// - Single periodic CSI report // - Single periodic CSI report
if (uci_cfg->o_ack == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) { if (uci_cfg->ack.count == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) {
*resource = uci_cfg->csi[0].pucch_resource; *resource = uci_cfg->csi[0].pucch_resource;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -139,7 +139,7 @@ static int test_pucch_format1(srsran_pucch_nr_t* pucch,
// Estimate channel // Estimate channel
TESTASSERT(srsran_dmrs_pucch_format1_estimate( TESTASSERT(srsran_dmrs_pucch_format1_estimate(
pucch, &carrier, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS); pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS);
TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f); TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f);
TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f); TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f);
@ -148,7 +148,7 @@ static int test_pucch_format1(srsran_pucch_nr_t* pucch,
// Decode PUCCH // Decode PUCCH
uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
TESTASSERT(srsran_pucch_nr_format1_decode( TESTASSERT(srsran_pucch_nr_format1_decode(
pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits) == pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) ==
SRSRAN_SUCCESS); SRSRAN_SUCCESS);
// Check received bits // Check received bits
@ -186,13 +186,14 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
resource.start_symbol_idx += starting_symbol_stride) { resource.start_symbol_idx += starting_symbol_stride) {
srsran_uci_cfg_nr_t uci_cfg = {}; srsran_uci_cfg_nr_t uci_cfg = {};
for (uci_cfg.o_ack = SRSRAN_PUCCH_NR_FORMAT2_MIN_NOF_BITS; uci_cfg.o_ack <= SRSRAN_UCI_NR_MAX_ACK_BITS; for (uci_cfg.ack.count = SRSRAN_PUCCH_NR_FORMAT2_MIN_NOF_BITS;
uci_cfg.o_ack++) { uci_cfg.ack.count <= SRSRAN_HARQ_ACK_MAX_NOF_BITS;
uci_cfg.ack.count++) {
srsran_uci_value_nr_t uci_value = {}; srsran_uci_value_nr_t uci_value = {};
// Maximum code rate is reserved // Maximum code rate is reserved
uint32_t max_code_rate_end = SRSRAN_PUCCH_NR_MAX_CODE_RATE; uint32_t max_code_rate_end = SRSRAN_PUCCH_NR_MAX_CODE_RATE;
if (uci_cfg.o_ack == 11) { if (uci_cfg.ack.count == 11) {
max_code_rate_end = SRSRAN_PUCCH_NR_MAX_CODE_RATE - 1; max_code_rate_end = SRSRAN_PUCCH_NR_MAX_CODE_RATE - 1;
} }
@ -207,7 +208,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
for (resource.starting_prb = 0; resource.starting_prb < (carrier.nof_prb - resource.nof_prb); for (resource.starting_prb = 0; resource.starting_prb < (carrier.nof_prb - resource.nof_prb);
resource.starting_prb += starting_prb_stride) { resource.starting_prb += starting_prb_stride) {
// Generate ACKs // Generate ACKs
for (uint32_t i = 0; i < uci_cfg.o_ack; i++) { for (uint32_t i = 0; i < uci_cfg.ack.count; i++) {
uci_value.ack[i] = (uint8_t)srsran_random_uniform_int_dist(random_gen, 0, 1); uci_value.ack[i] = (uint8_t)srsran_random_uniform_int_dist(random_gen, 0, 1);
} }
@ -224,8 +225,8 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
&awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR); &awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR);
// Estimate channel // Estimate channel
TESTASSERT(srsran_dmrs_pucch_format2_estimate( TESTASSERT(srsran_dmrs_pucch_format2_estimate(pucch, cfg, &slot, &resource, slot_symbols, chest_res) ==
pucch, &carrier, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS); SRSRAN_SUCCESS);
INFO("RSRP=%+.2f; EPRE=%+.2f; SNR=%+.2f;", INFO("RSRP=%+.2f; EPRE=%+.2f; SNR=%+.2f;",
chest_res->rsrp_dBfs, chest_res->rsrp_dBfs,
chest_res->epre_dBfs, chest_res->epre_dBfs,
@ -243,7 +244,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
TESTASSERT(uci_value_rx.valid == true); TESTASSERT(uci_value_rx.valid == true);
// Check received ACKs // Check received ACKs
for (uint32_t i = 0; i < uci_cfg.o_ack; i++) { for (uint32_t i = 0; i < uci_cfg.ack.count; i++) {
TESTASSERT(uci_value.ack[i] == uci_value_rx.ack[i]); TESTASSERT(uci_value.ack[i] == uci_value_rx.ack[i]);
} }
} }

@ -234,7 +234,7 @@ int main(int argc, char** argv)
// Generate HARQ ACK bits // Generate HARQ ACK bits
if (nof_ack_bits > 0) { if (nof_ack_bits > 0) {
pusch_cfg.uci.o_ack = nof_ack_bits; pusch_cfg.uci.ack.count = nof_ack_bits;
for (uint32_t i = 0; i < nof_ack_bits; i++) { for (uint32_t i = 0; i < nof_ack_bits; i++) {
data_tx.uci.ack[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1); data_tx.uci.ack[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1);
} }
@ -275,9 +275,7 @@ int main(int argc, char** argv)
} }
chest.nof_re = pusch_cfg.grant.tb->nof_re; chest.nof_re = pusch_cfg.grant.tb->nof_re;
srsran_pusch_res_nr_t* data_rx_vec[SRSRAN_MAX_TB] = {}; if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, &data_rx) <
data_rx_vec[0] = &data_rx;
if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, data_rx_vec) <
SRSRAN_SUCCESS) { SRSRAN_SUCCESS) {
ERROR("Error encoding"); ERROR("Error encoding");
goto clean_exit; goto clean_exit;

@ -165,8 +165,8 @@ static int uci_nr_pack_ack_sr(const srsran_uci_cfg_nr_t* cfg, const srsran_uci_v
int A = 0; int A = 0;
// Append ACK bits // Append ACK bits
srsran_vec_u8_copy(&sequence[A], value->ack, cfg->o_ack); srsran_vec_u8_copy(&sequence[A], value->ack, cfg->ack.count);
A += cfg->o_ack; A += cfg->ack.count;
// Append SR bits // Append SR bits
uint8_t* bits = &sequence[A]; uint8_t* bits = &sequence[A];
@ -186,8 +186,8 @@ static int uci_nr_unpack_ack_sr(const srsran_uci_cfg_nr_t* cfg, uint8_t* sequenc
int A = 0; int A = 0;
// Append ACK bits // Append ACK bits
srsran_vec_u8_copy(value->ack, &sequence[A], cfg->o_ack); srsran_vec_u8_copy(value->ack, &sequence[A], cfg->ack.count);
A += cfg->o_ack; A += cfg->ack.count;
// Append SR bits // Append SR bits
uint8_t* bits = &sequence[A]; uint8_t* bits = &sequence[A];
@ -207,8 +207,8 @@ static int uci_nr_pack_ack_sr_csi(const srsran_uci_cfg_nr_t* cfg, const srsran_u
int A = 0; int A = 0;
// Append ACK bits // Append ACK bits
srsran_vec_u8_copy(&sequence[A], value->ack, cfg->o_ack); srsran_vec_u8_copy(&sequence[A], value->ack, cfg->ack.count);
A += cfg->o_ack; A += cfg->ack.count;
// Append SR bits // Append SR bits
uint8_t* bits = &sequence[A]; uint8_t* bits = &sequence[A];
@ -236,8 +236,8 @@ static int uci_nr_unpack_ack_sr_csi(const srsran_uci_cfg_nr_t* cfg, uint8_t* seq
int A = 0; int A = 0;
// Append ACK bits // Append ACK bits
srsran_vec_u8_copy(value->ack, &sequence[A], cfg->o_ack); srsran_vec_u8_copy(value->ack, &sequence[A], cfg->ack.count);
A += cfg->o_ack; A += cfg->ack.count;
// Append SR bits // Append SR bits
uint8_t* bits = &sequence[A]; uint8_t* bits = &sequence[A];
@ -265,11 +265,11 @@ static int uci_nr_A(const srsran_uci_cfg_nr_t* cfg)
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (o_csi == 0) { if (o_csi == 0) {
return cfg->o_ack + cfg->o_sr; return cfg->ack.count + cfg->o_sr;
} }
// 6.3.1.1.2 CSI only // 6.3.1.1.2 CSI only
if (cfg->o_ack == 0 && cfg->o_sr == 0) { if (cfg->ack.count == 0 && cfg->o_sr == 0) {
return o_csi; return o_csi;
} }
@ -288,7 +288,7 @@ static int uci_nr_pack_pucch(const srsran_uci_cfg_nr_t* cfg, const srsran_uci_va
} }
// 6.3.1.1.2 CSI only // 6.3.1.1.2 CSI only
if (cfg->o_ack == 0 && cfg->o_sr == 0) { if (cfg->ack.count == 0 && cfg->o_sr == 0) {
return srsran_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, sequence, SRSRAN_UCI_NR_MAX_NOF_BITS); return srsran_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, sequence, SRSRAN_UCI_NR_MAX_NOF_BITS);
} }
@ -306,7 +306,7 @@ static int uci_nr_unpack_pucch(const srsran_uci_cfg_nr_t* cfg, uint8_t* sequence
} }
// 6.3.1.1.2 CSI only // 6.3.1.1.2 CSI only
if (cfg->o_ack == 0 && cfg->o_sr == 0) { if (cfg->ack.count == 0 && cfg->o_sr == 0) {
ERROR("CSI only are not implemented"); ERROR("CSI only are not implemented");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -989,16 +989,16 @@ uint32_t srsran_uci_nr_total_bits(const srsran_uci_cfg_nr_t* uci_cfg)
return 0; return 0;
} }
return uci_cfg->o_ack + uci_cfg->o_sr + srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); return uci_cfg->ack.count + uci_cfg->o_sr + srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
} }
uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uint32_t str_len) uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uint32_t str_len)
{ {
uint32_t len = 0; uint32_t len = 0;
if (uci_data->cfg.o_ack > 0) { if (uci_data->cfg.ack.count > 0) {
char str_ack[10]; char str_ack[10];
srsran_vec_sprint_bin(str_ack, (uint32_t)sizeof(str_ack), uci_data->value.ack, uci_data->cfg.o_ack); srsran_vec_sprint_bin(str_ack, (uint32_t)sizeof(str_ack), uci_data->value.ack, uci_data->cfg.ack.count);
len = srsran_print_check(str, str_len, len, "ack=%s ", str_ack); len = srsran_print_check(str, str_len, len, "ack=%s ", str_ack);
} }
@ -1075,7 +1075,7 @@ int srsran_uci_nr_encode_pusch_ack(srsran_uci_nr_t* q,
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
} }
int A = cfg->o_ack; int A = cfg->ack.count;
// 6.3.2.1 UCI bit sequence generation // 6.3.2.1 UCI bit sequence generation
// 6.3.2.1.1 HARQ-ACK // 6.3.2.1.1 HARQ-ACK
@ -1088,7 +1088,7 @@ int srsran_uci_nr_encode_pusch_ack(srsran_uci_nr_t* q,
UCI_NR_INFO_TX("No HARQ-ACK to mux"); UCI_NR_INFO_TX("No HARQ-ACK to mux");
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} else { } else {
srsran_vec_u8_copy(q->bit_sequence, value->ack, cfg->o_ack); srsran_vec_u8_copy(q->bit_sequence, value->ack, cfg->ack.count);
} }
// Compute total of encoded bits according to 6.3.2.4 Rate matching // Compute total of encoded bits according to 6.3.2.4 Rate matching
@ -1111,12 +1111,12 @@ int srsran_uci_nr_decode_pusch_ack(srsran_uci_nr_t* q,
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
} }
int A = cfg->o_ack; int A = cfg->ack.count;
// 6.3.2.1 UCI bit sequence generation // 6.3.2.1 UCI bit sequence generation
// 6.3.2.1.1 HARQ-ACK // 6.3.2.1.1 HARQ-ACK
bool has_csi_part2 = srsran_csi_has_part2(cfg->csi, cfg->nof_csi); bool has_csi_part2 = srsran_csi_has_part2(cfg->csi, cfg->nof_csi);
if (cfg->pusch.K_sum == 0 && cfg->nof_csi > 1 && !has_csi_part2 && cfg->o_ack < 2) { if (cfg->pusch.K_sum == 0 && cfg->nof_csi > 1 && !has_csi_part2 && cfg->ack.count < 2) {
A = 2; A = 2;
} }
@ -1187,7 +1187,7 @@ int srsran_uci_nr_pusch_csi1_nof_bits(const srsran_uci_cfg_nr_t* cfg)
ERROR("Errpr calculating CSI part 1 number of bits"); ERROR("Errpr calculating CSI part 1 number of bits");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
uint32_t O_ack = SRSRAN_MAX(2, cfg->o_ack); uint32_t O_ack = SRSRAN_MAX(2, cfg->ack.count);
int Q_csi1_prime = uci_nr_pusch_Q_prime_csi1(&cfg->pusch, (uint32_t)O_csi1, O_ack); int Q_csi1_prime = uci_nr_pusch_Q_prime_csi1(&cfg->pusch, (uint32_t)O_csi1, O_ack);
if (Q_csi1_prime < SRSRAN_SUCCESS) { if (Q_csi1_prime < SRSRAN_SUCCESS) {

@ -37,12 +37,12 @@ int rf_get_available_devices(char** devnames, int max_strlen)
int srsran_rf_set_rx_gain_th(srsran_rf_t* rf, double gain) int srsran_rf_set_rx_gain_th(srsran_rf_t* rf, double gain)
{ {
pthread_mutex_lock(&rf->mutex);
if (gain > rf->cur_rx_gain + 2 || gain < rf->cur_rx_gain - 2) { if (gain > rf->cur_rx_gain + 2 || gain < rf->cur_rx_gain - 2) {
pthread_mutex_lock(&rf->mutex);
rf->new_rx_gain = gain; rf->new_rx_gain = gain;
pthread_cond_signal(&rf->cond); pthread_cond_signal(&rf->cond);
pthread_mutex_unlock(&rf->mutex);
} }
pthread_mutex_unlock(&rf->mutex);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -62,6 +62,7 @@ typedef struct {
pthread_mutex_t tx_config_mutex; pthread_mutex_t tx_config_mutex;
pthread_mutex_t rx_config_mutex; pthread_mutex_t rx_config_mutex;
pthread_mutex_t decim_mutex; pthread_mutex_t decim_mutex;
pthread_mutex_t rx_gain_mutex;
} rf_zmq_handler_t; } rf_zmq_handler_t;
void update_rates(rf_zmq_handler_t* handler, double srate); void update_rates(rf_zmq_handler_t* handler, double srate);
@ -205,7 +206,9 @@ int rf_zmq_open_multi(char* args, void** h, uint32_t nof_channels)
bzero(handler, sizeof(rf_zmq_handler_t)); bzero(handler, sizeof(rf_zmq_handler_t));
*h = handler; *h = handler;
handler->base_srate = ZMQ_BASERATE_DEFAULT_HZ; // Sample rate for 100 PRB cell handler->base_srate = ZMQ_BASERATE_DEFAULT_HZ; // Sample rate for 100 PRB cell
pthread_mutex_lock(&handler->rx_gain_mutex);
handler->rx_gain = 0.0; handler->rx_gain = 0.0;
pthread_mutex_unlock(&handler->rx_gain_mutex);
handler->info.max_rx_gain = ZMQ_MAX_GAIN_DB; handler->info.max_rx_gain = ZMQ_MAX_GAIN_DB;
handler->info.min_rx_gain = ZMQ_MIN_GAIN_DB; handler->info.min_rx_gain = ZMQ_MIN_GAIN_DB;
handler->info.max_tx_gain = ZMQ_MAX_GAIN_DB; handler->info.max_tx_gain = ZMQ_MAX_GAIN_DB;
@ -229,6 +232,9 @@ int rf_zmq_open_multi(char* args, void** h, uint32_t nof_channels)
if (pthread_mutex_init(&handler->decim_mutex, NULL)) { if (pthread_mutex_init(&handler->decim_mutex, NULL)) {
perror("Mutex init"); perror("Mutex init");
} }
if (pthread_mutex_init(&handler->rx_gain_mutex, NULL)) {
perror("Mutex init");
}
// parse args // parse args
if (args && strlen(args)) { if (args && strlen(args)) {
@ -417,6 +423,7 @@ int rf_zmq_close(void* h)
pthread_mutex_destroy(&handler->tx_config_mutex); pthread_mutex_destroy(&handler->tx_config_mutex);
pthread_mutex_destroy(&handler->rx_config_mutex); pthread_mutex_destroy(&handler->rx_config_mutex);
pthread_mutex_destroy(&handler->decim_mutex); pthread_mutex_destroy(&handler->decim_mutex);
pthread_mutex_destroy(&handler->rx_gain_mutex);
// Free all // Free all
free(handler); free(handler);
@ -472,7 +479,9 @@ int rf_zmq_set_rx_gain(void* h, double gain)
{ {
if (h) { if (h) {
rf_zmq_handler_t* handler = (rf_zmq_handler_t*)h; rf_zmq_handler_t* handler = (rf_zmq_handler_t*)h;
pthread_mutex_lock(&handler->rx_gain_mutex);
handler->rx_gain = gain; handler->rx_gain = gain;
pthread_mutex_unlock(&handler->rx_gain_mutex);
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -497,7 +506,9 @@ double rf_zmq_get_rx_gain(void* h)
double ret = 0.0; double ret = 0.0;
if (h) { if (h) {
rf_zmq_handler_t* handler = (rf_zmq_handler_t*)h; rf_zmq_handler_t* handler = (rf_zmq_handler_t*)h;
pthread_mutex_lock(&handler->rx_gain_mutex);
ret = handler->rx_gain; ret = handler->rx_gain;
pthread_mutex_unlock(&handler->rx_gain_mutex);
} }
return ret; return ret;
} }
@ -672,7 +683,7 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl
// receive samples // receive samples
srsran_timestamp_t ts_tx = {}, ts_rx = {}; srsran_timestamp_t ts_tx = {}, ts_rx = {};
srsran_timestamp_init_uint64(&ts_tx, handler->transmitter[0].nsamples, handler->base_srate); srsran_timestamp_init_uint64(&ts_tx, rf_zmq_tx_get_nsamples(&handler->transmitter[0]), handler->base_srate);
srsran_timestamp_init_uint64(&ts_rx, handler->next_rx_ts, handler->base_srate); srsran_timestamp_init_uint64(&ts_rx, handler->next_rx_ts, handler->base_srate);
rf_zmq_info(handler->id, " - next rx time: %d + %.3f\n", ts_rx.full_secs, ts_rx.frac_secs); rf_zmq_info(handler->id, " - next rx time: %d + %.3f\n", ts_rx.full_secs, ts_rx.frac_secs);
rf_zmq_info(handler->id, " - next tx time: %d + %.3f\n", ts_tx.full_secs, ts_tx.frac_secs); rf_zmq_info(handler->id, " - next tx time: %d + %.3f\n", ts_tx.full_secs, ts_tx.frac_secs);
@ -775,7 +786,9 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl
} }
// Set gain // Set gain
pthread_mutex_lock(&handler->rx_gain_mutex);
float scale = srsran_convert_dB_to_amplitude(handler->rx_gain); float scale = srsran_convert_dB_to_amplitude(handler->rx_gain);
pthread_mutex_unlock(&handler->rx_gain_mutex);
for (uint32_t c = 0; c < handler->nof_channels; c++) { for (uint32_t c = 0; c < handler->nof_channels; c++) {
if (buffers[c]) { if (buffers[c]) {
srsran_vec_sc_prod_cfc(buffers[c], scale, buffers[c], nsamples); srsran_vec_sc_prod_cfc(buffers[c], scale, buffers[c], nsamples);

@ -106,6 +106,8 @@ SRSRAN_API int rf_zmq_tx_align(rf_zmq_tx_t* q, uint64_t ts);
SRSRAN_API int rf_zmq_tx_baseband(rf_zmq_tx_t* q, cf_t* buffer, uint32_t nsamples); SRSRAN_API int rf_zmq_tx_baseband(rf_zmq_tx_t* q, cf_t* buffer, uint32_t nsamples);
SRSRAN_API int rf_zmq_tx_get_nsamples(rf_zmq_tx_t* q);
SRSRAN_API int rf_zmq_tx_zeros(rf_zmq_tx_t* q, uint32_t nsamples); SRSRAN_API int rf_zmq_tx_zeros(rf_zmq_tx_t* q, uint32_t nsamples);
SRSRAN_API bool rf_zmq_tx_match_freq(rf_zmq_tx_t* q, uint32_t freq_hz); SRSRAN_API bool rf_zmq_tx_match_freq(rf_zmq_tx_t* q, uint32_t freq_hz);

@ -209,6 +209,14 @@ int rf_zmq_tx_baseband(rf_zmq_tx_t* q, cf_t* buffer, uint32_t nsamples)
return n; return n;
} }
int rf_zmq_tx_get_nsamples(rf_zmq_tx_t* q)
{
pthread_mutex_lock(&q->mutex);
int ret = q->nsamples;
pthread_mutex_unlock(&q->mutex);
return ret;
}
int rf_zmq_tx_zeros(rf_zmq_tx_t* q, uint32_t nsamples) int rf_zmq_tx_zeros(rf_zmq_tx_t* q, uint32_t nsamples)
{ {
pthread_mutex_lock(&q->mutex); pthread_mutex_lock(&q->mutex);

@ -20,57 +20,58 @@
*/ */
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include "srsran/phy/ue/ue_dl_nr.h" #include "srsran/phy/phch/harq_ack.h"
#include "srsran/phy/utils/debug.h"
#include <getopt.h> #include <getopt.h>
static int test_case_1() static int test_case_1()
{ {
// Set configuration // Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {}; srsran_harq_ack_cfg_hl_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information // Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {}; srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1; ack_info.nof_cc = 1;
ack_info.use_pusch = true; ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {}; srsran_harq_ack_m_t m = {};
m.value[0] = 1; m.value[0] = 1;
m.present = true; m.present = true;
m.resource.k1 = 8; m.resource.k1 = 8;
m.resource.v_dai_dl = 0; m.resource.v_dai_dl = 0;
m.value[0] = 1; m.value[0] = 1;
m.present = true; m.present = true;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5; m.resource.k1 = 5;
m.resource.v_dai_dl = 2; m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6; m.resource.k1 = 6;
m.resource.v_dai_dl = 1; m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4; m.resource.k1 = 4;
m.resource.v_dai_dl = 3; m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 3; m.resource.k1 = 3;
m.resource.v_dai_dl = 0; m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace // Print trace
char str[512] = {}; char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str); INFO("%s", str);
// Generate UCI data // Generate UCI data
srsran_uci_data_nr_t uci_data = {}; srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_pack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data // Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5); TESTASSERT(uci_data.cfg.ack.count == 5);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -78,49 +79,56 @@ static int test_case_1()
static int test_case_2() static int test_case_2()
{ {
// Set configuration // Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {}; srsran_harq_ack_cfg_hl_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information // Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {}; srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1; ack_info.nof_cc = 1;
ack_info.use_pusch = true; ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {}; srsran_harq_ack_m_t m = {};
m.value[0] = 1; m.value[0] = 1;
m.present = true; m.present = true;
m.resource.k1 = 7; m.resource.k1 = 7;
m.resource.v_dai_dl = 1; m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6; m.resource.k1 = 6;
m.resource.v_dai_dl = 2; m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 8; m.resource.k1 = 8;
m.resource.v_dai_dl = 0; m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5; m.resource.k1 = 5;
m.resource.v_dai_dl = 3; m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4; m.resource.k1 = 4;
m.resource.v_dai_dl = 0; m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace // Print trace
char str[512] = {}; char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str); INFO("%s", str);
// Generate UCI data // Generate UCI data
srsran_uci_data_nr_t uci_data = {}; srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS); TESTASSERT(srsran_harq_ack_pack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data // Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5); TESTASSERT(uci_data.cfg.ack.count == 5);
// Unpack HARQ ACK UCI data
srsran_pdsch_ack_nr_t ack_info_rx = ack_info;
TESTASSERT(srsran_harq_ack_unpack(&cfg, &uci_data, &ack_info_rx) == SRSRAN_SUCCESS);
// Assert unpacked data
TESTASSERT(memcmp(&ack_info, &ack_info_rx, sizeof(srsran_pdsch_ack_nr_t)) == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -599,255 +599,6 @@ int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q,
return len; return len;
} }
// Implements TS 38.213 Table 9.1.3-1: Value of counter DAI in DCI format 1_0 and of counter DAI or total DAI DCI format
// 1_1
static uint32_t ue_dl_nr_V_DL_DAI(uint32_t dai)
{
return dai + 1;
}
static int ue_dl_nr_gen_ack_type2(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data)
{
bool harq_ack_spatial_bundling =
ack_info->use_pusch ? cfg->harq_ack_spatial_bundling_pusch : cfg->harq_ack_spatial_bundling_pucch;
uint8_t* o_ack = uci_data->value.ack;
uint32_t m = 0; // PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion index: lower index corresponds to
// earlier PDCCH with DCI format 1_0 or DCI format 1_1 monitoring occasion
uint32_t j = 0;
uint32_t V_temp = 0;
uint32_t V_temp2 = 0;
uint32_t N_DL_cells = ack_info->nof_cc; // number of serving cells configured by higher layers for the UE
// The following code follows the exact pseudo-code provided in TS 38.213 9.1.3.1 Type-2 HARQ-ACK codebook ...
while (m < SRSRAN_UCI_NR_MAX_M) {
uint32_t c = 0; // serving cell index: lower indexes correspond to lower RRC indexes of corresponding cell
while (c < N_DL_cells) {
// Get ACK information of serving cell c for the PDCH monitoring occasion m
const srsran_pdsch_ack_m_nr_t* ack = &ack_info->cc[c].m[m];
// Get DAI counter value
uint32_t V_DL_CDAI = ue_dl_nr_V_DL_DAI(ack->resource.v_dai_dl);
uint32_t V_DL_TDAI = ack->resource.dci_format_1_1 ? ue_dl_nr_V_DL_DAI(ack->resource.v_dai_dl) : UINT32_MAX;
// Get ACK values
uint32_t ack_tb0 = ack->value[0];
uint32_t ack_tb1 = ack->value[1];
// For a PDCCH monitoring occasion with DCI format 1_0 or DCI format 1_1 in the active DL BWP of a serving cell,
// when a UE receives a PDSCH with one transport block and the value of maxNrofCodeWordsScheduledByDCI is 2, the
// HARQ-ACK information is associated with the first transport block and the UE generates a NACK for the second
// transport block if harq-ACK-SpatialBundlingPUCCH is not provided and generates HARQ-ACK information with
// value of ACK for the second transport block if harq-ACK-SpatialBundlingPUCCH is provided.
if (cfg->max_cw_sched_dci_is_2 && ack->second_tb_present) {
ack_tb1 = harq_ack_spatial_bundling ? 1 : 0;
}
// if PDCCH monitoring occasion m is before an active DL BWP change on serving cell c or an active UL
// BWP change on the PCell and an active DL BWP change is not triggered by a DCI format 1_1 in PDCCH
// monitoring occasion m
if (ack->dl_bwp_changed || ack->ul_bwp_changed) {
c = c + 1;
} else {
if (ack->present) {
// Load ACK resource data into UCI info
uci_data->cfg.pucch.resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id;
uci_data->cfg.pucch.rnti = ack_info->cc[c].m[m].resource.rnti;
if (V_DL_CDAI <= V_temp) {
j = j + 1;
}
V_temp = V_DL_CDAI;
if (V_DL_TDAI == UINT32_MAX) {
V_temp2 = V_DL_CDAI;
} else {
V_temp2 = V_DL_TDAI;
}
// if harq-ACK-SpatialBundlingPUCCH is not provided and m is a monitoring occasion for PDCCH with DCI format
// 1_0 or DCI format 1_1 and the UE is configured by maxNrofCodeWordsScheduledByDCI with reception of two
// transport blocks for at least one configured DL BWP of at least one serving cell,
if (!harq_ack_spatial_bundling && cfg->max_cw_sched_dci_is_2) {
o_ack[8 * j + 2 * (V_DL_CDAI - 1) + 0] = ack_tb0;
o_ack[8 * j + 2 * (V_DL_CDAI - 1) + 1] = ack_tb1;
}
// elseif harq-ACK-SpatialBundlingPUCCH is provided to the UE and m is a monitoring occasion for
// PDCCH with DCI format 1_1 and the UE is configured by maxNrofCodeWordsScheduledByDCI with
// reception of two transport blocks in at least one configured DL BWP of a serving cell,
else if (harq_ack_spatial_bundling && ack->resource.dci_format_1_1 && cfg->max_cw_sched_dci_is_2) {
o_ack[4 * j + (V_DL_CDAI - 1)] = ack_tb0 & ack_tb1;
}
// else
else {
o_ack[4 * j + (V_DL_CDAI - 1)] = ack_tb0;
}
}
c = c + 1;
}
}
m = m + 1;
}
if (V_temp2 < V_temp) {
j = j + 1;
}
// if harq-ACK-SpatialBundlingPUCCH is not provided to the UE and the UE is configured by
// maxNrofCodeWordsScheduledByDCI with reception of two transport blocks for at least one configured DL BWP of a
// serving cell,
if (!harq_ack_spatial_bundling && cfg->max_cw_sched_dci_is_2) {
uci_data->cfg.o_ack = 2 * (4 * j + V_temp2);
} else {
uci_data->cfg.o_ack = 4 * j + V_temp2;
}
// Implement here SPS PDSCH reception
// ...
return SRSRAN_SUCCESS;
}
int ue_dl_nr_pdsch_k1(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg, const srsran_dci_dl_nr_t* dci_dl)
{
// For DCI format 1_0, the PDSCH-to-HARQ_feedback timing indicator field values map to {1, 2, 3, 4, 5, 6, 7, 8}
if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) {
return (int)dci_dl->harq_feedback + 1;
}
// For DCI format 1_1, if present, the PDSCH-to-HARQ_feedback timing indicator field values map to values for a set of
// number of slots provided by dl-DataToUL-ACK as defined in Table 9.2.3-1.
if (dci_dl->harq_feedback >= SRSRAN_MAX_NOF_DL_DATA_TO_UL || dci_dl->harq_feedback >= cfg->nof_dl_data_to_ul_ack) {
ERROR("Out-of-range PDSCH-to-HARQ feedback index (%d, max %d)", dci_dl->harq_feedback, cfg->nof_dl_data_to_ul_ack);
return SRSRAN_ERROR;
}
return (int)cfg->dl_data_to_ul_ack[dci_dl->harq_feedback];
}
int srsran_ue_dl_nr_pdsch_ack_resource(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
const srsran_dci_dl_nr_t* dci_dl,
srsran_pdsch_ack_resource_nr_t* pdsch_ack_resource)
{
if (cfg == NULL || dci_dl == NULL || pdsch_ack_resource == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Calculate Data to UL ACK timing k1
int k1 = ue_dl_nr_pdsch_k1(cfg, dci_dl);
if (k1 < SRSRAN_ERROR) {
ERROR("Error calculating K1");
return SRSRAN_ERROR;
}
// Fill PDSCH resource
pdsch_ack_resource->dci_format_1_1 = (dci_dl->ctx.format == srsran_dci_format_nr_1_1);
pdsch_ack_resource->k1 = k1;
pdsch_ack_resource->v_dai_dl = dci_dl->dai;
pdsch_ack_resource->rnti = dci_dl->ctx.rnti;
pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource;
return SRSRAN_SUCCESS;
}
int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
const srsran_pdsch_ack_nr_t* ack_info,
srsran_uci_data_nr_t* uci_data)
{
// Check inputs
if (cfg == NULL || ack_info == NULL || uci_data == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// According TS 38.213 9.1.2 Type-1 HARQ-ACK codebook determination
if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_semi_static) {
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = semi-static.
ERROR("Type-1 HARQ-ACK codebook determination is NOT implemented");
return SRSRAN_ERROR;
}
// According TS 38.213 9.1.3 Type-2 HARQ-ACK codebook determination
if (cfg->harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic) {
// This clause applies if the UE is configured with pdsch-HARQ-ACK-Codebook = dynamic.
return ue_dl_nr_gen_ack_type2(cfg, ack_info, uci_data);
}
ERROR("No HARQ-ACK codebook determination is NOT implemented");
return SRSRAN_ERROR;
}
int srsran_ue_dl_nr_ack_insert_m(srsran_pdsch_ack_nr_t* ack_info, const srsran_pdsch_ack_m_nr_t* m)
{
// Check inputs
if (ack_info == NULL || m == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Protect SCell index and extract information
if (m->resource.scell_idx >= SRSRAN_MAX_CARRIERS) {
ERROR("Serving cell index (%d) exceeds maximum", m->resource.scell_idx);
return SRSRAN_ERROR;
}
srsran_pdsch_ack_cc_nr_t* cc = &ack_info->cc[m->resource.scell_idx];
// Find insertion index
uint32_t idx = cc->M; // Append at the end by default
for (uint32_t i = 0; i < cc->M; i++) {
if (cc->m[i].resource.k1 < m->resource.k1) {
idx = i;
break;
}
}
// Increment count
cc->M += 1;
// Make space for insertion
for (uint32_t i = cc->M - 1; i > idx; i--) {
cc->m[i] = cc->m[i - 1];
}
// Actual insertion
cc->m[idx] = *m;
return SRSRAN_SUCCESS;
}
uint32_t srsran_ue_dl_nr_ack_info(const srsran_pdsch_ack_nr_t* ack_info, char* str, uint32_t str_len)
{
uint32_t len = 0;
if (ack_info == NULL || str == NULL) {
return 0;
}
// Print base info
len = srsran_print_check(
str, str_len, len, "use_pusch=%c nof_cc=%d\n", ack_info->use_pusch ? 'y' : 'n', ack_info->nof_cc);
// Iterate all carriers
for (uint32_t cc = 0; cc < ack_info->nof_cc; cc++) {
len = srsran_print_check(str, str_len, len, " CC %d: M=%d\n", cc, ack_info->cc[cc].M);
for (uint32_t m = 0; m < ack_info->cc[cc].M; m++) {
if (ack_info->cc[cc].m[m].present) {
len = srsran_print_check(str,
str_len,
len,
" m %d: k1=%d dai=%d ack=%d\n",
m,
ack_info->cc[cc].m[m].resource.k1,
ack_info->cc[cc].m[m].resource.v_dai_dl,
ack_info->cc[cc].m[m].value[0]);
}
}
}
return len;
}
int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q, int srsran_ue_dl_nr_csi_measure_trs(const srsran_ue_dl_nr_t* q,
const srsran_slot_cfg_t* slot_cfg, const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set, const srsran_csi_rs_nzp_set_t* csi_rs_nzp_set,

@ -159,7 +159,7 @@ static int ue_ul_nr_encode_pucch_format1(srsran_ue_ul_nr_t* q,
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {}; uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
// Set ACK bits // Set ACK bits
uint32_t nof_bits = SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_data->cfg.o_ack); uint32_t nof_bits = SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_data->cfg.ack.count);
for (uint32_t i = 0; i < nof_bits; i++) { for (uint32_t i = 0; i < nof_bits; i++) {
b[i] = uci_data->value.ack[i]; b[i] = uci_data->value.ack[i];
} }
@ -269,7 +269,7 @@ int srsran_ue_ul_nr_pucch_info(const srsran_pucch_nr_resource_t* resource,
int len = 0; int len = 0;
// Append PDSCH info // Append PDSCH info
len += srsran_pucch_nr_tx_info(resource, uci_data, &str[len], str_len - len); len += srsran_pucch_nr_info(resource, uci_data, &str[len], str_len - len);
return len; return len;
} }

@ -31,6 +31,7 @@
#define TX_MOD_BASE(x) (((x)-vt_a) % 1024) #define TX_MOD_BASE(x) (((x)-vt_a) % 1024)
#define LCID (parent->lcid) #define LCID (parent->lcid)
#define RB_NAME (parent->rb_name.c_str()) #define RB_NAME (parent->rb_name.c_str())
#define MAX_SDUS_PER_PDU (128)
namespace srsran { namespace srsran {
@ -674,12 +675,11 @@ bool rlc_am_lte::rlc_am_lte_tx::poll_required()
int rlc_am_lte::rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) int rlc_am_lte::rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes)
{ {
int pdu_len = parent->rx.get_status_pdu(&tx_status, nof_bytes); int pdu_len = parent->rx.get_status_pdu(&tx_status, nof_bytes);
log_rlc_am_status_pdu_to_string(logger.debug, "%s", &tx_status); if (pdu_len == SRSRAN_ERROR) {
if (pdu_len > 0 && nof_bytes >= static_cast<uint32_t>(pdu_len)) { logger.debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", RB_NAME);
pdu_len = 0;
} else if (pdu_len > 0 && nof_bytes >= static_cast<uint32_t>(pdu_len)) {
log_rlc_am_status_pdu_to_string(logger.info, "%s Tx status PDU - %s", &tx_status, RB_NAME); log_rlc_am_status_pdu_to_string(logger.info, "%s Tx status PDU - %s", &tx_status, RB_NAME);
parent->rx.reset_status();
if (cfg.t_status_prohibit > 0 && status_prohibit_timer.is_valid()) { if (cfg.t_status_prohibit > 0 && status_prohibit_timer.is_valid()) {
// re-arm timer // re-arm timer
status_prohibit_timer.run(); status_prohibit_timer.run();
@ -1056,7 +1056,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
} }
// Pull SDUs from queue // Pull SDUs from queue
while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < RLC_AM_WINDOW_SIZE) { while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < MAX_SDUS_PER_PDU) {
if (not segment_pool.has_segments()) { if (not segment_pool.has_segments()) {
logger.info("Can't build a PDU segment - No segment resources available"); logger.info("Can't build a PDU segment - No segment resources available");
if (pdu_ptr != pdu->msg) { if (pdu_ptr != pdu->msg) {
@ -1851,15 +1851,13 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus()
void rlc_am_lte::rlc_am_lte_rx::reset_status() void rlc_am_lte::rlc_am_lte_rx::reset_status()
{ {
std::lock_guard<std::mutex> lock(mutex);
do_status = false; do_status = false;
poll_received = false; poll_received = false;
} }
bool rlc_am_lte::rlc_am_lte_rx::get_do_status() bool rlc_am_lte::rlc_am_lte_rx::get_do_status()
{ {
std::lock_guard<std::mutex> lock(mutex); return do_status.load(std::memory_order_relaxed);
return do_status;
} }
void rlc_am_lte::rlc_am_lte_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes) void rlc_am_lte::rlc_am_lte_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes)
@ -1930,9 +1928,14 @@ void rlc_am_lte::rlc_am_lte_rx::timer_expired(uint32_t timeout_id)
} }
// Called from Tx object to pack status PDU that doesn't exceed a given size // Called from Tx object to pack status PDU that doesn't exceed a given size
// If lock-acquisition fails, return -1. Otherwise it returns the length of the generated PDU.
int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size)
{ {
std::lock_guard<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
if (not lock.owns_lock()) {
return SRSRAN_ERROR;
}
status->N_nack = 0; status->N_nack = 0;
status->ack_sn = vr_r; // start with lower edge of the rx window status->ack_sn = vr_r; // start with lower edge of the rx window
@ -1972,13 +1975,19 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui
i = (i + 1) % MOD; i = (i + 1) % MOD;
} }
// valid PDU could be generated
reset_status();
return rlc_am_packed_length(status); return rlc_am_packed_length(status);
} }
// Called from Tx object to obtain length of the full status PDU // Called from Tx object to obtain length of the full status PDU
int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length() int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length()
{ {
std::lock_guard<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
if (not lock.owns_lock()) {
return 0;
}
rlc_status_pdu_t status = {}; rlc_status_pdu_t status = {};
status.ack_sn = vr_ms; status.ack_sn = vr_ms;
uint32_t i = vr_r; uint32_t i = vr_r;

@ -78,9 +78,9 @@ sys_metrics_t sys_metrics_processor::get_metrics()
uint32_t measure_interval_ms = uint32_t measure_interval_ms =
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_query_time).count(); std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_query_time).count();
// The time elapsed between 2 measures must be greater that 100 milliseconds. // The time elapsed between 2 measures must be greater that 10 milliseconds.
if (measure_interval_ms < 100u) { if (measure_interval_ms < 10u) {
logger.warning("Interval less than 100ms, skipping measurement."); logger.info("Interval less than 10ms, skipping measurement.");
return create_null_metrics(); return create_null_metrics();
} }

@ -19,7 +19,7 @@
# #
add_executable(s1ap_asn1_test s1ap_test.cc) add_executable(s1ap_asn1_test s1ap_test.cc)
target_link_libraries(s1ap_asn1_test srsran_common srsran_asn1 s1ap_asn1) target_link_libraries(s1ap_asn1_test srsran_common srsran_asn1 s1ap_asn1 ${ATOMIC_LIBS})
add_test(s1ap_asn1_test s1ap_asn1_test) add_test(s1ap_asn1_test s1ap_asn1_test)
add_executable(srsran_asn1_rrc_mcch_test srsran_asn1_rrc_mcch_test.cc) add_executable(srsran_asn1_rrc_mcch_test srsran_asn1_rrc_mcch_test.cc)
@ -54,9 +54,9 @@ add_executable(rrc_asn1_test rrc_test.cc)
target_link_libraries(rrc_asn1_test rrc_asn1 asn1_utils srsran_common) target_link_libraries(rrc_asn1_test rrc_asn1 asn1_utils srsran_common)
add_test(rrc_asn1_test rrc_asn1_test) add_test(rrc_asn1_test rrc_asn1_test)
add_executable(rrc_nr_asn1_test rrc_nr_test.cc) add_executable(srsran_asn1_rrc_nr_test srsran_asn1_rrc_nr_test.cc)
target_link_libraries(rrc_nr_asn1_test rrc_nr_asn1 asn1_utils srsran_common) target_link_libraries(srsran_asn1_rrc_nr_test rrc_nr_asn1 asn1_utils srsran_common)
add_test(rrc_nr_asn1_test rrc_nr_asn1_test) add_test(srsran_asn1_rrc_nr_test srsran_asn1_rrc_nr_test)
add_executable(ngap_asn1_test ngap_test.cc) add_executable(ngap_asn1_test ngap_test.cc)
target_link_libraries(ngap_asn1_test ngap_nr_asn1 srsran_common) target_link_libraries(ngap_asn1_test ngap_nr_asn1 srsran_common)
@ -71,3 +71,6 @@ target_link_libraries(rrc_asn1_decoder rrc_asn1)
add_executable(nas_decoder nas_decoder.cc) add_executable(nas_decoder nas_decoder.cc)
target_link_libraries(nas_decoder srsran_asn1) target_link_libraries(nas_decoder srsran_asn1)
add_executable(nas_5g_msg_test nas_5g_msg_test.cc)
target_link_libraries(nas_5g_msg_test nas_5g_msg)

File diff suppressed because it is too large Load Diff

@ -116,7 +116,7 @@ int make_phy_harq_ack_cfg_test()
phys_cell_group_cfg_s phys_cell_group_cfg = {}; phys_cell_group_cfg_s phys_cell_group_cfg = {};
phys_cell_group_cfg.pdsch_harq_ack_codebook = phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value; phys_cell_group_cfg.pdsch_harq_ack_codebook = phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value;
srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg; srsran_harq_ack_cfg_hl_t srsran_ue_dl_nr_harq_ack_cfg;
TESTASSERT(make_phy_harq_ack_cfg(phys_cell_group_cfg, &srsran_ue_dl_nr_harq_ack_cfg) == true); TESTASSERT(make_phy_harq_ack_cfg(phys_cell_group_cfg, &srsran_ue_dl_nr_harq_ack_cfg) == true);
TESTASSERT(srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic); TESTASSERT(srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic);

@ -19,19 +19,15 @@
* *
*/ */
#include "srsran/asn1/rrc/dl_dcch_msg.h"
#include "srsran/asn1/rrc/ul_dcch_msg.h" #include "srsran/asn1/rrc/ul_dcch_msg.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/common/bcd_helpers.h" #include "srsran/common/bcd_helpers.h"
#include "srsran/common/test_common.h"
#include "srsran/interfaces/rrc_interface_types.h" #include "srsran/interfaces/rrc_interface_types.h"
#include <iostream> #include <iostream>
#define TESTASSERT(cond) \ #define JSON_OUTPUT 0
{ \
if (!(cond)) { \
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
return -1; \
} \
}
using namespace asn1; using namespace asn1;
using namespace asn1::rrc; using namespace asn1::rrc;
@ -92,6 +88,136 @@ int meas_obj_test()
return 0; return 0;
} }
int test_meas_config()
{
// RRC reconfig with NR meas config
uint8_t tv[] = {0x20, 0x10, 0x15, 0xc0, 0x40, 0x00, 0x00, 0x96, 0x32, 0x18, 0x10, 0xa8, 0x04, 0xd6, 0xa0,
0x10, 0x02, 0x01, 0x02, 0x18, 0x9a, 0x00, 0x03, 0x41, 0x81, 0x0e, 0x00, 0x01, 0x38, 0x00,
0xc0, 0x40, 0x61, 0xc0, 0x00, 0x83, 0x00, 0x31, 0x02, 0x90, 0x60, 0x88, 0x00};
asn1::SRSASN_CODE err;
cbit_ref bref(tv, sizeof(tv));
dl_dcch_msg_s recfg_msg_unpacked;
TESTASSERT(recfg_msg_unpacked.unpack(bref) == SRSASN_SUCCESS);
TESTASSERT(test_pack_unpack_consistency(recfg_msg_unpacked) == SRSASN_SUCCESS);
#if JSON_OUTPUT
int unpacked_len = bref.distance_bytes();
asn1::json_writer json_writer1;
recfg_msg_unpacked.to_json(json_writer1);
srslog::fetch_basic_logger("ASN1").info(
tv, sizeof(tv), "RRC config unpacked (%d B): \n %s", unpacked_len, json_writer1.to_string().c_str());
#endif
dl_dcch_msg_s recfg_msg_packed;
recfg_msg_packed.msg.set_c1();
recfg_msg_packed.msg.c1().set_rrc_conn_recfg(); // = dl_dcch_msg_type_c::c1_c_::types::rrc_conn_recfg;
recfg_msg_packed.msg.c1().rrc_conn_recfg().crit_exts.set_c1();
recfg_msg_packed.msg.c1().rrc_conn_recfg().crit_exts.c1().set_rrc_conn_recfg_r8();
recfg_msg_packed.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8().meas_cfg_present = true;
meas_cfg_s& meas_cfg = recfg_msg_packed.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8().meas_cfg;
meas_cfg.meas_obj_to_add_mod_list_present = true;
meas_cfg.meas_obj_to_add_mod_list.resize(2);
auto& meas_obj = meas_cfg.meas_obj_to_add_mod_list[0];
meas_obj.meas_obj_id = 1;
meas_obj.meas_obj.set_meas_obj_eutra();
meas_obj.meas_obj.meas_obj_eutra().carrier_freq = 300;
meas_obj.meas_obj.meas_obj_eutra().allowed_meas_bw = allowed_meas_bw_opts::mbw50;
meas_obj.meas_obj.meas_obj_eutra().presence_ant_port1 = false;
meas_obj.meas_obj.meas_obj_eutra().neigh_cell_cfg.from_number(0b01);
auto& meas_obj2 = meas_cfg.meas_obj_to_add_mod_list[1];
meas_obj2.meas_obj_id = 2;
meas_obj2.meas_obj.set_meas_obj_nr_r15();
meas_obj2.meas_obj.meas_obj_nr_r15().carrier_freq_r15 = 634176;
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.meas_timing_cfg_r15.periodicity_and_offset_r15.set_sf20_r15();
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.meas_timing_cfg_r15.ssb_dur_r15 =
asn1::rrc::mtc_ssb_nr_r15_s::ssb_dur_r15_opts::sf1;
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.subcarrier_spacing_ssb_r15 =
asn1::rrc::rs_cfg_ssb_nr_r15_s::subcarrier_spacing_ssb_r15_opts::khz30;
meas_obj2.meas_obj.meas_obj_nr_r15().ext = true;
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.set_present(true);
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.get()->set_setup() = 78;
// report config
meas_cfg.report_cfg_to_add_mod_list_present = true;
meas_cfg.report_cfg_to_add_mod_list.resize(1);
auto& report_cfg = meas_cfg.report_cfg_to_add_mod_list[0];
report_cfg.report_cfg_id = 1;
report_cfg.report_cfg.set_report_cfg_inter_rat();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.set_event();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.set_event_b1_nr_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.set_nr_rsrp_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.nr_rsrp_r15() = 56;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.event_b1_nr_r15().report_on_leave_r15 =
false;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().hysteresis = 0;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().time_to_trigger = time_to_trigger_opts::ms100;
report_cfg.report_cfg.report_cfg_inter_rat().max_report_cells = 8;
report_cfg.report_cfg.report_cfg_inter_rat().report_interv = report_interv_opts::ms120;
report_cfg.report_cfg.report_cfg_inter_rat().report_amount = report_cfg_inter_rat_s::report_amount_opts::r1;
report_cfg.report_cfg.report_cfg_inter_rat().ext = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.set_present(true);
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrp = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrq = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_sinr = true;
// measIdToAddModList
meas_cfg.meas_id_to_add_mod_list_present = true;
meas_cfg.meas_id_to_add_mod_list.resize(1);
auto& meas_id = meas_cfg.meas_id_to_add_mod_list[0];
meas_id.meas_id = 1;
meas_id.meas_obj_id = 2;
meas_id.report_cfg_id = 1;
// quantityConfig
meas_cfg.quant_cfg_present = true;
meas_cfg.quant_cfg.quant_cfg_eutra_present = true;
meas_cfg.quant_cfg.ext = true;
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.set_present(true);
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()->resize(1);
auto& meas_quant = meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()[0];
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15_present = true;
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15 = filt_coef_opts::fc3;
// measGapConfig
meas_cfg.meas_gap_cfg_present = true;
meas_cfg.meas_gap_cfg.set_setup();
meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16;
uint8_t pack_buffer[1024];
bit_ref bref2(pack_buffer, sizeof(pack_buffer));
recfg_msg_packed.pack(bref2);
int packed_len = bref2.distance_bytes();
TESTASSERT(sizeof(tv) == packed_len);
TESTASSERT(memcmp(pack_buffer, tv, packed_len) == 0);
#if JSON_OUTPUT
asn1::json_writer json_writer2;
recfg_msg_packed.to_json(json_writer2);
srslog::fetch_basic_logger("ASN1").info(
pack_buffer, packed_len, "RRC config packed (%d B): \n %s", packed_len, json_writer2.to_string().c_str());
#endif
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false); auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false);
@ -100,7 +226,8 @@ int main(int argc, char** argv)
srslog::init(); srslog::init();
TESTASSERT(meas_obj_test() == 0); TESTASSERT(meas_obj_test() == SRSRAN_SUCCESS);
TESTASSERT(test_meas_config() == SRSRAN_SUCCESS);
return 0; return 0;
} }

@ -23,6 +23,8 @@
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include <cstdio> #include <cstdio>
#define JSON_OUTPUT 0
using namespace asn1; using namespace asn1;
using namespace asn1::rrc_nr; using namespace asn1::rrc_nr;
@ -184,9 +186,11 @@ int test_ue_rrc_reconfiguration()
TESTASSERT(rrc_recfg.unpack(bref) == SRSASN_SUCCESS); TESTASSERT(rrc_recfg.unpack(bref) == SRSASN_SUCCESS);
TESTASSERT(rrc_recfg.rrc_transaction_id == 0); TESTASSERT(rrc_recfg.rrc_transaction_id == 0);
#if JSON_OUTPUT
json_writer jw; json_writer jw;
rrc_recfg.to_json(jw); rrc_recfg.to_json(jw);
srslog::fetch_basic_logger("RRC").info("RRC Reconfig: \n %s", jw.to_string().c_str()); srslog::fetch_basic_logger("RRC").info("RRC Reconfig: \n %s", jw.to_string().c_str());
#endif
TESTASSERT(rrc_recfg.crit_exts.type() == asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg); TESTASSERT(rrc_recfg.crit_exts.type() == asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg);
TESTASSERT(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group_present == true); TESTASSERT(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group_present == true);
@ -195,9 +199,11 @@ int test_ue_rrc_reconfiguration()
cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(), cbit_ref bref0(rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.data(),
rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.size()); rrc_recfg.crit_exts.rrc_recfg().secondary_cell_group.size());
TESTASSERT(cell_group_cfg.unpack(bref0) == SRSASN_SUCCESS); TESTASSERT(cell_group_cfg.unpack(bref0) == SRSASN_SUCCESS);
// json_writer jw1; #if JSON_OUTPUT
// cell_group_cfg.to_json(jw1); json_writer jw1;
// srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: \n %s", jw1.to_string().c_str()); cell_group_cfg.to_json(jw1);
srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: \n %s", jw1.to_string().c_str());
#endif
TESTASSERT(cell_group_cfg.cell_group_id == 1); TESTASSERT(cell_group_cfg.cell_group_id == 1);
TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list_present == true); TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list_present == true);
TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list.size() == 1); TESTASSERT(cell_group_cfg.rlc_bearer_to_add_mod_list.size() == 1);
@ -210,18 +216,76 @@ int test_ue_rrc_reconfiguration()
int test_radio_bearer_config() int test_radio_bearer_config()
{ {
uint8_t rrc_msg[] = "\x14\x09\x28\x17\x87\xc0\x0c\x28"; uint8_t rrc_msg[] = "\x14\x09\x28\x17\x87\xc0\x0c\x28";
uint32_t rrc_msg_len = sizeof(rrc_msg);
cbit_ref bref(&rrc_msg[0], sizeof(rrc_msg)); cbit_ref bref(&rrc_msg[0], sizeof(rrc_msg));
radio_bearer_cfg_s radio_bearer_cfg; radio_bearer_cfg_s radio_bearer_cfg;
TESTASSERT(radio_bearer_cfg.unpack(bref) == SRSASN_SUCCESS); TESTASSERT(radio_bearer_cfg.unpack(bref) == SRSASN_SUCCESS);
// json_writer jw; #if JSON_OUTPUT
// radio_bearer_cfg.to_json(jw); json_writer jw;
// srslog::fetch_basic_logger("RRC").info("RRC Bearer CFG Message: \n %s", jw.to_string().c_str()); radio_bearer_cfg.to_json(jw);
srslog::fetch_basic_logger("RRC").info("RRC Bearer CFG Message: \n %s", jw.to_string().c_str());
#endif
TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list_present == true); TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list_present == true);
TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list.size() == 1); TESTASSERT(radio_bearer_cfg.drb_to_add_mod_list.size() == 1);
TESTASSERT(radio_bearer_cfg.security_cfg_present == true); TESTASSERT(radio_bearer_cfg.security_cfg_present == true);
TESTASSERT(radio_bearer_cfg.security_cfg.security_algorithm_cfg_present == true); TESTASSERT(radio_bearer_cfg.security_cfg.security_algorithm_cfg_present == true);
TESTASSERT(radio_bearer_cfg.security_cfg.key_to_use_present == true); TESTASSERT(radio_bearer_cfg.security_cfg.key_to_use_present == true);
// full RRC reconfig pack
rrc_recfg_s reconfig;
reconfig.rrc_transaction_id = 0;
rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.set_rrc_recfg();
recfg_ies.radio_bearer_cfg_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list.resize(1);
auto& drb_item = recfg_ies.radio_bearer_cfg.drb_to_add_mod_list[0];
drb_item.drb_id = 1;
drb_item.cn_assoc_present = true;
drb_item.cn_assoc.set_eps_bearer_id() = 5;
drb_item.pdcp_cfg_present = true;
drb_item.pdcp_cfg.ciphering_disabled_present = true;
drb_item.pdcp_cfg.drb_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_dl_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_dl = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_dl_opts::len18bits;
drb_item.pdcp_cfg.drb.pdcp_sn_size_ul_present = true;
drb_item.pdcp_cfg.drb.pdcp_sn_size_ul = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_ul_opts::len18bits;
drb_item.pdcp_cfg.drb.discard_timer_present = true;
drb_item.pdcp_cfg.drb.discard_timer = asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_opts::ms100;
drb_item.pdcp_cfg.drb.hdr_compress.set_not_used();
drb_item.pdcp_cfg.t_reordering_present = true;
drb_item.pdcp_cfg.t_reordering = asn1::rrc_nr::pdcp_cfg_s::t_reordering_opts::ms0;
recfg_ies.radio_bearer_cfg.security_cfg_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.key_to_use_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.key_to_use = asn1::rrc_nr::security_cfg_s::key_to_use_opts::secondary;
recfg_ies.radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true;
recfg_ies.radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_opts::nea2;
uint8_t buffer[1024];
asn1::bit_ref bref_pack(buffer, sizeof(buffer));
TESTASSERT(reconfig.pack(bref_pack) == asn1::SRSASN_SUCCESS);
TESTASSERT(test_pack_unpack_consistency(reconfig) == SRSASN_SUCCESS);
#if JSON_OUTPUT
reconfig.to_json(jw);
srslog::fetch_basic_logger("RRC").info("RRC Reconfig Message: \n %s", jw.to_string().c_str());
#endif
// only pack the radio bearer config to compare against TV
asn1::bit_ref bref_pack2(buffer, sizeof(buffer));
radio_bearer_cfg_s& radio_bearer_cfg_pack = recfg_ies.radio_bearer_cfg;
TESTASSERT(radio_bearer_cfg_pack.pack(bref_pack2) == asn1::SRSASN_SUCCESS);
#if JSON_OUTPUT
radio_bearer_cfg_pack.to_json(jw);
srslog::fetch_basic_logger("RRC").info("Radio bearer config Message: \n %s", jw.to_string().c_str());
#endif
// TODO: messages don't match yet
// TESTASSERT(bref_pack2.distance_bytes() == sizeof(rrc_msg));
// TESTASSERT(memcmp(rrc_msg, buffer, sizeof(rrc_msg)) == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -271,7 +335,7 @@ int test_cell_group_config()
TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg_present == true); TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg_present == true); TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present == true); TESTASSERT(cell_group_cfg.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync_present = true); TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common_present == true); TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci_present == true); TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci_present == true);
TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci == 500); TESTASSERT(cell_group_cfg.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci == 500);
@ -300,9 +364,123 @@ int test_cell_group_config()
TESTASSERT(rach_cfg_common.rach_cfg_generic.ra_resp_win == asn1::rrc_nr::rach_cfg_generic_s::ra_resp_win_opts::sl10); TESTASSERT(rach_cfg_common.rach_cfg_generic.ra_resp_win == asn1::rrc_nr::rach_cfg_generic_s::ra_resp_win_opts::sl10);
TESTASSERT(rach_cfg_common.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present == true); TESTASSERT(rach_cfg_common.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present == true);
// asn1::json_writer json_writer; #if JSON_OUTPUT
// cell_group_cfg.to_json(json_writer); asn1::json_writer json_writer;
// srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: Content: %s\n", json_writer.to_string().c_str()); cell_group_cfg.to_json(json_writer);
srslog::fetch_basic_logger("RRC").info("RRC Secondary Cell Group: Content: %s\n", json_writer.to_string().c_str());
#endif
// pack it again
cell_group_cfg_s cell_group_cfg_pack;
cell_group_cfg_pack.sp_cell_cfg_present = true;
cell_group_cfg_pack.sp_cell_cfg.serv_cell_idx_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg_present = true;
// TODO: add setup
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg_present = true;
auto& pdcch_cfg = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg.set_setup();
// TODO: add PDCCH config
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg_present = true;
auto& pdsch_cfg = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg.set_setup();
// TODO: add PDSCH config
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = true;
cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup();
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.new_ue_id = 17943;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.smtc.release();
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.t304 = recfg_with_sync_s::t304_opts::ms1000;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ss_pbch_block_pwr = 0;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dmrs_type_a_position =
asn1::rrc_nr::serving_cell_cfg_common_s::dmrs_type_a_position_opts::pos2;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci = 500;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_subcarrier_spacing_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_subcarrier_spacing =
subcarrier_spacing_opts::khz30;
// DL config
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl
.absolute_freq_ssb_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.absolute_freq_ssb =
632640;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.freq_band_list
.push_back(78);
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.absolute_freq_point_a =
632316;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl
.scs_specific_carrier_list.resize(1);
auto& dl_carrier = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl
.scs_specific_carrier_list[0];
dl_carrier.offset_to_carrier = 0;
dl_carrier.subcarrier_spacing = subcarrier_spacing_opts::khz15;
dl_carrier.carrier_bw = 52;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params
.location_and_bw = 14025;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params
.subcarrier_spacing = subcarrier_spacing_opts::khz15;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp
.pdcch_cfg_common_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common
.set_setup();
// TODO: add PDCCH config
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp
.pdsch_cfg_common_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdsch_cfg_common
.set_setup();
// TODO: add PDSCH config
// UL config
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.dummy = time_align_timer_opts::ms500;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul
.scs_specific_carrier_list.resize(1);
auto& ul_carrier = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul
.scs_specific_carrier_list[0];
ul_carrier.offset_to_carrier = 0;
ul_carrier.subcarrier_spacing = subcarrier_spacing_opts::khz15;
ul_carrier.carrier_bw = 52;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp_present = true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params
.location_and_bw = 14025;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params
.subcarrier_spacing = subcarrier_spacing_opts::khz15;
// TODO: add config field for RACH
#if 0
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present=true;
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.set_setup();
cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup().prach_root_seq_idx = 10;
#endif
uint8_t buffer[1024];
asn1::bit_ref bref_pack(buffer, sizeof(buffer));
TESTASSERT(cell_group_cfg_pack.pack(bref_pack) == asn1::SRSASN_SUCCESS);
TESTASSERT(test_pack_unpack_consistency(cell_group_cfg_pack) == SRSASN_SUCCESS);
#if JSON_OUTPUT
int packed_len = bref_pack.distance_bytes();
asn1::json_writer json_writer2;
cell_group_cfg_pack.to_json(json_writer2);
srslog::fetch_basic_logger("RRC").info(
buffer, packed_len, "Cell group config repacked (%d B): \n %s", packed_len, json_writer2.to_string().c_str());
#endif
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -19,7 +19,7 @@
* *
*/ */
#include "srsran/phy/enb/enb_dl_nr.h" #include "srsran/phy/gnb/gnb_dl.h"
#include "srsran/phy/phch/ra_dl_nr.h" #include "srsran/phy/phch/ra_dl_nr.h"
#include "srsran/phy/phch/ra_nr.h" #include "srsran/phy/phch/ra_nr.h"
#include "srsran/phy/ue/ue_dl_nr.h" #include "srsran/phy/ue/ue_dl_nr.h"
@ -153,13 +153,13 @@ static int parse_args(int argc, char** argv)
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl, static int work_gnb_dl(srsran_gnb_dl_t* gnb_dl,
srsran_slot_cfg_t* slot, srsran_slot_cfg_t* slot,
srsran_search_space_t* search_space, srsran_search_space_t* search_space,
srsran_dci_location_t* dci_location, srsran_dci_location_t* dci_location,
uint8_t** data_tx) uint8_t** data_tx)
{ {
if (srsran_enb_dl_nr_base_zero(enb_dl) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_base_zero(gnb_dl) < SRSRAN_SUCCESS) {
ERROR("Error setting base to zero"); ERROR("Error setting base to zero");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -179,18 +179,18 @@ static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl,
dci_dl.rv = 0; dci_dl.rv = 0;
// Put actual DCI // Put actual DCI
if (srsran_enb_dl_nr_pdcch_put_dl(enb_dl, slot, &dci_dl) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_pdcch_put_dl(gnb_dl, slot, &dci_dl) < SRSRAN_SUCCESS) {
ERROR("Error putting PDCCH"); ERROR("Error putting PDCCH");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Put PDSCH transmission // Put PDSCH transmission
if (srsran_enb_dl_nr_pdsch_put(enb_dl, slot, &pdsch_cfg, data_tx) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_pdsch_put(gnb_dl, slot, &pdsch_cfg, data_tx) < SRSRAN_SUCCESS) {
ERROR("Error putting PDSCH"); ERROR("Error putting PDSCH");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
srsran_enb_dl_nr_gen_signal(enb_dl); srsran_gnb_dl_gen_signal(gnb_dl);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -223,7 +223,7 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot, srsran_
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret = SRSRAN_ERROR; int ret = SRSRAN_ERROR;
srsran_enb_dl_nr_t enb_dl = {}; srsran_gnb_dl_t gnb_dl = {};
srsran_ue_dl_nr_t ue_dl = {}; srsran_ue_dl_nr_t ue_dl = {};
srsran_pdsch_res_nr_t pdsch_res = {}; srsran_pdsch_res_nr_t pdsch_res = {};
srsran_random_t rand_gen = srsran_random_init(1234); srsran_random_t rand_gen = srsran_random_init(1234);
@ -260,11 +260,11 @@ int main(int argc, char** argv)
ue_dl_args.pdcch.measure_evm = true; ue_dl_args.pdcch.measure_evm = true;
ue_dl_args.nof_max_prb = carrier.nof_prb; ue_dl_args.nof_max_prb = carrier.nof_prb;
srsran_enb_dl_nr_args_t enb_dl_args = {}; srsran_gnb_dl_args_t gnb_dl_args = {};
enb_dl_args.nof_tx_antennas = 1; gnb_dl_args.nof_tx_antennas = 1;
enb_dl_args.pdsch.sch.disable_simd = false; gnb_dl_args.pdsch.sch.disable_simd = false;
enb_dl_args.pdcch.disable_simd = false; gnb_dl_args.pdcch.disable_simd = false;
enb_dl_args.nof_max_prb = carrier.nof_prb; gnb_dl_args.nof_max_prb = carrier.nof_prb;
srsran_pdcch_cfg_nr_t pdcch_cfg = {}; srsran_pdcch_cfg_nr_t pdcch_cfg = {};
@ -294,7 +294,7 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
if (srsran_enb_dl_nr_init(&enb_dl, buffer_gnb, &enb_dl_args)) { if (srsran_gnb_dl_init(&gnb_dl, buffer_gnb, &gnb_dl_args)) {
ERROR("Error UE DL"); ERROR("Error UE DL");
goto clean_exit; goto clean_exit;
} }
@ -313,12 +313,12 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
if (srsran_enb_dl_nr_set_carrier(&enb_dl, &carrier)) { if (srsran_gnb_dl_set_carrier(&gnb_dl, &carrier)) {
ERROR("Error setting SCH NR carrier"); ERROR("Error setting SCH NR carrier");
goto clean_exit; goto clean_exit;
} }
if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &pdcch_cfg, &dci_cfg)) { if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &dci_cfg)) {
ERROR("Error setting CORESET"); ERROR("Error setting CORESET");
goto clean_exit; goto clean_exit;
} }
@ -419,7 +419,7 @@ int main(int argc, char** argv)
dci_location.L = L; dci_location.L = L;
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
if (work_gnb_dl(&enb_dl, &slot, search_space, &dci_location, data_tx) < SRSRAN_ERROR) { if (work_gnb_dl(&gnb_dl, &slot, search_space, &dci_location, data_tx) < SRSRAN_ERROR) {
ERROR("Error running eNb DL"); ERROR("Error running eNb DL");
goto clean_exit; goto clean_exit;
} }
@ -510,7 +510,7 @@ int main(int argc, char** argv)
clean_exit: clean_exit:
srsran_random_free(rand_gen); srsran_random_free(rand_gen);
srsran_enb_dl_nr_free(&enb_dl); srsran_gnb_dl_free(&gnb_dl);
srsran_ue_dl_nr_free(&ue_dl); srsran_ue_dl_nr_free(&ue_dl);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (data_tx[i]) { if (data_tx[i]) {

@ -88,7 +88,8 @@ private:
srsran_slot_cfg_t ul_slot_cfg = {}; srsran_slot_cfg_t ul_slot_cfg = {};
srsran_pdcch_cfg_nr_t pdcch_cfg = {}; srsran_pdcch_cfg_nr_t pdcch_cfg = {};
srsran::rf_timestamp_t tx_time = {}; srsran::rf_timestamp_t tx_time = {};
srsran_enb_dl_nr_t gnb_dl = {}; srsran_gnb_dl_t gnb_dl = {};
srsran_gnb_ul_t gnb_ul = {};
std::vector<cf_t*> tx_buffer; ///< Baseband transmit buffers std::vector<cf_t*> tx_buffer; ///< Baseband transmit buffers
std::vector<cf_t*> rx_buffer; ///< Baseband receive buffers std::vector<cf_t*> rx_buffer; ///< Baseband receive buffers
}; };

@ -28,7 +28,9 @@
#define SRSRAN_ENB_STACK_LTE_H #define SRSRAN_ENB_STACK_LTE_H
#include "mac/mac.h" #include "mac/mac.h"
#include "mac/mac_nr.h"
#include "rrc/rrc.h" #include "rrc/rrc.h"
#include "rrc/rrc_nr.h"
#include "s1ap/s1ap.h" #include "s1ap/s1ap.h"
#include "srsran/common/task_scheduler.h" #include "srsran/common/task_scheduler.h"
#include "upper/gtpu.h" #include "upper/gtpu.h"
@ -128,6 +130,10 @@ private:
srslog::basic_logger& s1ap_logger; srslog::basic_logger& s1ap_logger;
srslog::basic_logger& gtpu_logger; srslog::basic_logger& gtpu_logger;
srslog::basic_logger& stack_logger; srslog::basic_logger& stack_logger;
srslog::basic_logger& rrc_nr_logger;
srslog::basic_logger& mac_nr_logger;
srslog::basic_logger& rlc_nr_logger;
srslog::basic_logger& pdcp_nr_logger;
// PCAP and trace option // PCAP and trace option
srsran::mac_pcap mac_pcap; srsran::mac_pcap mac_pcap;
@ -145,6 +151,12 @@ private:
srsenb::gtpu gtpu; srsenb::gtpu gtpu;
srsenb::s1ap s1ap; srsenb::s1ap s1ap;
// NR components for NSA mode
srsenb::mac_nr mac_nr;
srsenb::rlc rlc_nr;
srsenb::pdcp pdcp_nr;
srsenb::rrc_nr rrc_nr;
// RAT-specific interfaces // RAT-specific interfaces
phy_interface_stack_lte* phy = nullptr; phy_interface_stack_lte* phy = nullptr;

@ -84,6 +84,8 @@ public:
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override;
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override;
private: private:
void run_thread() final; void run_thread() final;

@ -27,6 +27,7 @@
#include "srsran/mac/mac_sch_pdu_nr.h" #include "srsran/mac/mac_sch_pdu_nr.h"
#include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsran/common/task_scheduler.h"
#include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h"
@ -49,7 +50,7 @@ struct mac_nr_args_t {
class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_rlc_nr class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_rlc_nr
{ {
public: public:
mac_nr(); mac_nr(srsran::task_sched_handle task_sched_);
~mac_nr(); ~mac_nr();
int init(const mac_nr_args_t& args_, int init(const mac_nr_args_t& args_,
@ -77,6 +78,8 @@ public:
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override;
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override;
private: private:
void get_dl_config(const uint32_t tti, void get_dl_config(const uint32_t tti,
@ -92,6 +95,9 @@ private:
rlc_interface_mac_nr* rlc_h = nullptr; rlc_interface_mac_nr* rlc_h = nullptr;
rrc_interface_mac_nr* rrc_h = nullptr; rrc_interface_mac_nr* rrc_h = nullptr;
// args
srsran::task_sched_handle task_sched;
std::unique_ptr<srsran::mac_pcap> pcap = nullptr; std::unique_ptr<srsran::mac_pcap> pcap = nullptr;
mac_nr_args_t args = {}; mac_nr_args_t args = {};
srslog::basic_logger& logger; srslog::basic_logger& logger;

@ -25,9 +25,9 @@
#include "srsran/adt/bounded_bitset.h" #include "srsran/adt/bounded_bitset.h"
#include "srsran/adt/bounded_vector.h" #include "srsran/adt/bounded_vector.h"
#include "srsran/adt/span.h" #include "srsran/adt/span.h"
#include "srsran/common/phy_cfg_nr.h"
#include "srsran/common/tti_point.h" #include "srsran/common/tti_point.h"
#include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include "srsran/phy/phch/dci_nr.h" #include "srsran/phy/phch/dci_nr.h"
namespace srsenb { namespace srsenb {

@ -76,6 +76,8 @@ private:
float ta_us; ///< TA measurement in microseconds float ta_us; ///< TA measurement in microseconds
} ta_meas_t; } ta_meas_t;
std::mutex mutex;
uint32_t meas_t_ms = 0; ///< Time counter in milliseconds uint32_t meas_t_ms = 0; ///< Time counter in milliseconds
uint32_t meas_count = 0; ///< Number of measures in the buffer uint32_t meas_count = 0; ///< Number of measures in the buffer
uint32_t meas_idx = 0; ///< Next mesurement index in the buffer uint32_t meas_idx = 0; ///< Next mesurement index in the buffer
@ -220,6 +222,7 @@ public:
*/ */
uint32_t push_value(float ta_us) uint32_t push_value(float ta_us)
{ {
std::lock_guard<std::mutex> lock(mutex);
// Put measurement if state is measurement // Put measurement if state is measurement
if (state == state_measure) { if (state == state_measure) {
// Set measurement // Set measurement
@ -247,6 +250,7 @@ public:
*/ */
uint32_t tick() uint32_t tick()
{ {
std::lock_guard<std::mutex> lock(mutex);
// Increase measurement timestamp counter // Increase measurement timestamp counter
meas_t_ms++; meas_t_ms++;

@ -173,6 +173,7 @@ public:
srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t enb_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 clear_old_buffers(uint32_t tti);
std::mutex metrics_mutex = {};
void metrics_read(mac_ue_metrics_t* metrics_); void metrics_read(mac_ue_metrics_t* metrics_);
void metrics_rx(bool crc, uint32_t tbs); void metrics_rx(bool crc, uint32_t tbs);
void metrics_tx(bool crc, uint32_t tbs); void metrics_tx(bool crc, uint32_t tbs);

@ -58,7 +58,8 @@ static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
class rrc final : public rrc_interface_pdcp, class rrc final : public rrc_interface_pdcp,
public rrc_interface_mac, public rrc_interface_mac,
public rrc_interface_rlc, public rrc_interface_rlc,
public rrc_interface_s1ap public rrc_interface_s1ap,
public rrc_eutra_interface_rrc_nr
{ {
public: public:
explicit rrc(srsran::task_sched_handle task_sched_); explicit rrc(srsran::task_sched_handle task_sched_);
@ -72,6 +73,15 @@ public:
s1ap_interface_rrc* s1ap, s1ap_interface_rrc* s1ap,
gtpu_interface_rrc* gtpu); gtpu_interface_rrc* gtpu);
int32_t init(const rrc_cfg_t& cfg_,
phy_interface_rrc_lte* phy,
mac_interface_rrc* mac,
rlc_interface_rrc* rlc,
pdcp_interface_rrc* pdcp,
s1ap_interface_rrc* s1ap,
gtpu_interface_rrc* gtpu,
rrc_nr_interface_rrc* rrc_nr);
void stop(); void stop();
void get_metrics(rrc_metrics_t& m); void get_metrics(rrc_metrics_t& m);
void tti_clock(); void tti_clock();
@ -124,6 +134,12 @@ public:
int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override; int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override;
// rrc_eutra_interface_rrc_nr
void sgnb_addition_ack(uint16_t rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) override;
void sgnb_addition_reject(uint16_t rnti) override;
// rrc_interface_pdcp // rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override;
void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) override; void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) override;
@ -164,6 +180,7 @@ private:
pdcp_interface_rrc* pdcp = nullptr; pdcp_interface_rrc* pdcp = nullptr;
gtpu_interface_rrc* gtpu = nullptr; gtpu_interface_rrc* gtpu = nullptr;
s1ap_interface_rrc* s1ap = nullptr; s1ap_interface_rrc* s1ap = nullptr;
rrc_nr_interface_rrc* rrc_nr = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
// derived params // derived params

@ -0,0 +1,113 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSENB_RRC_ENDC_H
#define SRSENB_RRC_ENDC_H
#include "rrc.h"
#include "rrc_ue.h"
#include "srsran/adt/fsm.h"
#include <map>
namespace srsenb {
/**
* @brief This procedure handles the secondary node (SgNB) addition for
* EUTRA-NR Dual connectivity (ENDC)
*
*/
class rrc::ue::rrc_endc : public srsran::fsm_t<rrc::ue::rrc_endc>
{
public:
// public events
struct user_crnti_upd_ev {
uint16_t crnti;
uint16_t temp_crnti;
};
struct ho_cancel_ev {
asn1::s1ap::cause_c cause;
ho_cancel_ev(const asn1::s1ap::cause_c& cause_) : cause(cause_) {}
};
rrc_endc(srsenb::rrc::ue* outer_ue);
bool fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg);
void handle_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps);
void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg);
void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15);
void handle_sgnb_addition_reject();
private:
// Send SgNB addition request to gNB
bool start_sgnb_addition();
bool is_endc_activation_running() const { return not is_in_state<idle_st>(); }
rrc::ue* rrc_ue = nullptr;
rrc* rrc_enb = nullptr;
srslog::basic_logger& logger;
// vars
bool endc_supported = false;
asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
// events
struct sgnb_add_req_sent_ev {};
struct sgnb_add_req_ack_ev {};
struct sgnb_add_req_reject_ev {};
struct prach_nr_received_ev {};
using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s;
using status_transfer_ev = asn1::s1ap::bearers_subject_to_status_transfer_list_l;
// states
struct idle_st {};
struct wait_sgnb_add_req_resp {};
struct wait_recfg_comp {};
struct wait_prach_nr {};
// FSM guards
// FSM transition handlers
void handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev);
void handle_sgnb_addition_request_sent(const sgnb_add_req_sent_ev& ev);
protected:
// states
state_list<idle_st, wait_sgnb_add_req_resp, wait_recfg_comp, wait_prach_nr> states{this,
idle_st{},
wait_sgnb_add_req_resp{},
wait_recfg_comp{},
wait_prach_nr{}};
// transitions
using fsm = rrc_endc;
// clang-format off
using transitions = transition_table<
// Start Target Event Action Guard
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< idle_st, wait_sgnb_add_req_resp, sgnb_add_req_sent_ev, nullptr >,
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
row< wait_sgnb_add_req_resp, wait_recfg_comp, sgnb_add_req_ack_ev >,
row< wait_sgnb_add_req_resp, idle_st, sgnb_add_req_reject_ev >,
row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete >
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
>;
// clang-format on
};
} // namespace srsenb
#endif // SRSENB_RRC_ENDC_H

@ -32,6 +32,7 @@
#include "srsran/common/task_scheduler.h" #include "srsran/common/task_scheduler.h"
#include "srsran/common/threads.h" #include "srsran/common/threads.h"
#include "srsran/common/timeout.h" #include "srsran/common/timeout.h"
#include "srsran/interfaces/enb_rrc_interfaces.h"
#include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/gnb_ngap_interfaces.h" #include "srsran/interfaces/gnb_ngap_interfaces.h"
#include "srsran/interfaces/gnb_rrc_nr_interfaces.h" #include "srsran/interfaces/gnb_rrc_nr_interfaces.h"
@ -69,18 +70,20 @@ struct rrc_nr_cfg_t {
class rrc_nr final : public rrc_interface_pdcp_nr, class rrc_nr final : public rrc_interface_pdcp_nr,
public rrc_interface_mac_nr, public rrc_interface_mac_nr,
public rrc_interface_rlc_nr, public rrc_interface_rlc_nr,
public rrc_interface_ngap_nr public rrc_interface_ngap_nr,
public rrc_nr_interface_rrc
{ {
public: public:
explicit rrc_nr(srsran::timer_handler* timers_); explicit rrc_nr(srsran::task_sched_handle task_sched_);
int32_t init(const rrc_nr_cfg_t& cfg, int32_t init(const rrc_nr_cfg_t& cfg,
phy_interface_stack_nr* phy, phy_interface_stack_nr* phy,
mac_interface_rrc_nr* mac, mac_interface_rrc_nr* mac,
rlc_interface_rrc_nr* rlc, rlc_interface_rrc_nr* rlc,
pdcp_interface_rrc_nr* pdcp, pdcp_interface_rrc_nr* pdcp,
ngap_interface_rrc_nr* ngap_, ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu); gtpu_interface_rrc_nr* gtpu,
rrc_eutra_interface_rrc_nr* rrc_eutra_);
void stop(); void stop();
@ -104,6 +107,10 @@ public:
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final; void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final;
void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) final; void notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) final;
// Interface for EUTRA RRC
int sgnb_addition_request(uint16_t rnti);
int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response);
class ue class ue
{ {
public: public:
@ -112,6 +119,8 @@ public:
void send_connection_setup(); void send_connection_setup();
void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg); void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg);
int handle_sgnb_addition_request();
// getters // getters
bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; } bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; }
bool is_idle() { return state == rrc_nr_state_t::RRC_IDLE; } bool is_idle() { return state == rrc_nr_state_t::RRC_IDLE; }
@ -139,9 +148,10 @@ private:
pdcp_interface_rrc_nr* pdcp = nullptr; pdcp_interface_rrc_nr* pdcp = nullptr;
gtpu_interface_rrc_nr* gtpu = nullptr; gtpu_interface_rrc_nr* gtpu = nullptr;
ngap_interface_rrc_nr* ngap = nullptr; ngap_interface_rrc_nr* ngap = nullptr;
rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr;
// args // args
srsran::timer_handler* timers = nullptr; srsran::task_sched_handle task_sched;
// derived // derived
uint32_t slot_dur_ms = 0; uint32_t slot_dur_ms = 0;

@ -34,6 +34,7 @@ class rrc::ue
{ {
public: public:
class rrc_mobility; class rrc_mobility;
class rrc_endc;
enum activity_timeout_type_t { enum activity_timeout_type_t {
MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs
UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout) UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout)
@ -117,6 +118,11 @@ public:
bool handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg); bool handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg);
void handle_ue_info_resp(const asn1::rrc::ue_info_resp_r9_s& msg, srsran::unique_byte_buffer_t pdu); void handle_ue_info_resp(const asn1::rrc::ue_info_resp_r9_s& msg, srsran::unique_byte_buffer_t pdu);
// SgNB handler
void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15);
void handle_sgnb_addition_reject();
void set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates); void set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates);
/// Helper to check UE ERABs /// Helper to check UE ERABs
@ -163,6 +169,7 @@ public:
bool connect_notified = false; bool connect_notified = false;
unique_rnti_ptr<rrc_mobility> mobility_handler; unique_rnti_ptr<rrc_mobility> mobility_handler;
unique_rnti_ptr<rrc_endc> endc_handler;
bool is_csfb = false; bool is_csfb = false;

@ -22,6 +22,7 @@
#include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/common/rnti_pool.h"
#include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/common/common_enb.h"
#include "srsenb/hdr/stack/mac/ue.h" #include "srsenb/hdr/stack/mac/ue.h"
#include "srsenb/hdr/stack/rrc/rrc_endc.h"
#include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/hdr/stack/rrc/rrc_ue.h" #include "srsenb/hdr/stack/rrc/rrc_ue.h"
#include "srsran/adt/pool/circular_stack_pool.h" #include "srsran/adt/pool/circular_stack_pool.h"
@ -30,8 +31,8 @@
namespace srsenb { namespace srsenb {
const static size_t UE_MEM_BLOCK_SIZE = const static size_t UE_MEM_BLOCK_SIZE = 1024 + sizeof(ue) + sizeof(rrc::ue) + sizeof(rrc::ue::rrc_mobility) +
sizeof(ue) + sizeof(rrc::ue) + sizeof(rrc::ue::rrc_mobility) + sizeof(srsran::rlc) + sizeof(srsran::pdcp); sizeof(rrc::ue::rrc_endc) + sizeof(srsran::rlc) + sizeof(srsran::pdcp);
srsran::circular_stack_pool<SRSENB_MAX_UES>* get_rnti_pool() srsran::circular_stack_pool<SRSENB_MAX_UES>* get_rnti_pool()
{ {

@ -30,6 +30,7 @@
#include "srsran/common/config_file.h" #include "srsran/common/config_file.h"
#include "srsran/common/crash_handler.h" #include "srsran/common/crash_handler.h"
#include "srsran/common/signal_handler.h" #include "srsran/common/signal_handler.h"
#include "srsran/common/tsan_options.h"
#include "srsran/srslog/event_trace.h" #include "srsran/srslog/event_trace.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"

@ -62,22 +62,41 @@ bool slot_worker::init(const args_t& args)
} }
// Prepare DL arguments // Prepare DL arguments
srsran_enb_dl_nr_args_t dl_args = {}; srsran_gnb_dl_args_t dl_args = {};
dl_args.pdsch.measure_time = true; dl_args.pdsch.measure_time = true;
dl_args.pdsch.max_layers = args.carrier.max_mimo_layers; dl_args.pdsch.max_layers = args.carrier.max_mimo_layers;
dl_args.pdsch.max_prb = args.carrier.nof_prb; dl_args.pdsch.max_prb = args.carrier.nof_prb;
dl_args.nof_tx_antennas = args.nof_tx_ports; dl_args.nof_tx_antennas = args.nof_tx_ports;
dl_args.nof_max_prb = args.carrier.nof_prb; dl_args.nof_max_prb = args.carrier.nof_prb;
// Initialise DL // Initialise DL
if (srsran_enb_dl_nr_init(&gnb_dl, tx_buffer.data(), &dl_args) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_init(&gnb_dl, tx_buffer.data(), &dl_args) < SRSRAN_SUCCESS) {
logger.error("Error gNb PHY init"); logger.error("Error gNb DL init");
return false; return false;
} }
// Set gNb carrier // Set gNb DL carrier
if (srsran_enb_dl_nr_set_carrier(&gnb_dl, &args.carrier) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_set_carrier(&gnb_dl, &args.carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting carrier"); logger.error("Error setting DL carrier");
return false;
}
// Prepare UL arguments
srsran_gnb_ul_args_t ul_args = {};
ul_args.pusch.measure_time = true;
ul_args.pusch.max_layers = args.carrier.max_mimo_layers;
ul_args.pusch.max_prb = args.carrier.nof_prb;
ul_args.nof_max_prb = args.carrier.nof_prb;
// Initialise UL
if (srsran_gnb_ul_init(&gnb_ul, rx_buffer[0], &ul_args) < SRSRAN_SUCCESS) {
logger.error("Error gNb DL init");
return false;
}
// Set gNb UL carrier
if (srsran_gnb_ul_set_carrier(&gnb_ul, &args.carrier) < SRSRAN_SUCCESS) {
logger.error("Error setting UL carrier");
return false; return false;
} }
@ -98,7 +117,8 @@ slot_worker::~slot_worker()
b = nullptr; b = nullptr;
} }
} }
srsran_enb_dl_nr_free(&gnb_dl); srsran_gnb_dl_free(&gnb_dl);
srsran_gnb_ul_free(&gnb_ul);
} }
cf_t* slot_worker::get_buffer_rx(uint32_t antenna_idx) cf_t* slot_worker::get_buffer_rx(uint32_t antenna_idx)
@ -140,14 +160,72 @@ bool slot_worker::work_ul()
return false; return false;
} }
// Demodulate
if (srsran_gnb_ul_fft(&gnb_ul) < SRSRAN_SUCCESS) {
logger.error("Error in demodulation");
return false;
}
// Decode PUCCH // Decode PUCCH
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) { for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) {
// ... stack_interface_phy_nr::pucch_info_t pucch_info = {};
pucch_info.uci_data.cfg = pucch.uci_cfg;
// Decode PUCCH
if (srsran_gnb_ul_get_pucch(&gnb_ul,
&ul_slot_cfg,
&pucch.pucch_cfg,
&pucch.resource,
&pucch_info.uci_data.cfg,
&pucch_info.uci_data.value) < SRSRAN_SUCCESS) {
logger.error("Error getting PUCCH");
return false;
}
// Inform stack
if (stack.pucch_info(ul_slot_cfg, pucch_info) < SRSRAN_SUCCESS) {
logger.error("Error pushing PUCCH information to stack");
return false;
}
// Log PUCCH decoding
if (logger.info.enabled()) {
std::array<char, 512> str;
srsran_gnb_ul_pucch_info(&gnb_ul, &pucch.resource, &pucch_info.uci_data, str.data(), (uint32_t)str.size());
logger.info("PUCCH: %s", str.data());
}
} }
// Decode PUSCH // Decode PUSCH
for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) { for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) {
// ... // Get payload PDU
stack_interface_phy_nr::pusch_info_t pusch_info = {};
pusch_info.uci_cfg = pusch.sch.uci;
pusch_info.pid = pusch.pid;
pusch_info.pusch_data.tb[0].payload = pusch.data[0];
pusch_info.pusch_data.tb[1].payload = pusch.data[1];
// Decode PUCCH
if (srsran_gnb_ul_get_pusch(&gnb_ul, &ul_slot_cfg, &pusch.sch, &pusch.sch.grant, &pusch_info.pusch_data) <
SRSRAN_SUCCESS) {
logger.error("Error getting PUSCH");
return false;
}
// Inform stack
if (stack.pusch_info(ul_slot_cfg, pusch_info) < SRSRAN_SUCCESS) {
logger.error("Error pushing PUSCH information to stack");
return false;
}
// Log PUSCH decoding
if (logger.info.enabled()) {
std::array<char, 512> str;
srsran_gnb_ul_pusch_info(&gnb_ul, &pusch.sch, &pusch_info.pusch_data, str.data(), (uint32_t)str.size());
logger.info("PUSCH: %s", str.data());
}
} }
return true; return true;
@ -157,12 +235,12 @@ bool slot_worker::work_dl()
{ {
// Retrieve Scheduling for the current processing DL slot // Retrieve Scheduling for the current processing DL slot
stack_interface_phy_nr::dl_sched_t dl_sched = {}; stack_interface_phy_nr::dl_sched_t dl_sched = {};
if (stack.get_dl_sched(ul_slot_cfg, dl_sched) < SRSRAN_SUCCESS) { if (stack.get_dl_sched(dl_slot_cfg, dl_sched) < SRSRAN_SUCCESS) {
logger.error("Error retrieving DL scheduling"); logger.error("Error retrieving DL scheduling");
return false; return false;
} }
if (srsran_enb_dl_nr_base_zero(&gnb_dl) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_base_zero(&gnb_dl) < SRSRAN_SUCCESS) {
logger.error("Error zeroeing RE grid"); logger.error("Error zeroeing RE grid");
return false; return false;
} }
@ -170,13 +248,13 @@ bool slot_worker::work_dl()
// Encode PDCCH for DL transmissions // Encode PDCCH for DL transmissions
for (const stack_interface_phy_nr::pdcch_dl_t& pdcch : dl_sched.pdcch_dl) { for (const stack_interface_phy_nr::pdcch_dl_t& pdcch : dl_sched.pdcch_dl) {
// Set PDCCH configuration, including DCI dedicated // Set PDCCH configuration, including DCI dedicated
if (srsran_enb_dl_nr_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error setting DL configuration"); logger.error("PDCCH: Error setting DL configuration");
return false; return false;
} }
// Put PDCCH message // Put PDCCH message
if (srsran_enb_dl_nr_pdcch_put_dl(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_pdcch_put_dl(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error putting DL message"); logger.error("PDCCH: Error putting DL message");
return false; return false;
} }
@ -184,7 +262,7 @@ bool slot_worker::work_dl()
// Log PDCCH information // Log PDCCH information
if (logger.info.enabled()) { if (logger.info.enabled()) {
std::array<char, 512> str = {}; std::array<char, 512> str = {};
srsran_enb_dl_nr_pdcch_dl_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size()); srsran_gnb_dl_pdcch_dl_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size());
logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx); logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
} }
} }
@ -192,13 +270,13 @@ bool slot_worker::work_dl()
// Encode PDCCH for UL transmissions // Encode PDCCH for UL transmissions
for (const stack_interface_phy_nr::pdcch_ul_t& pdcch : dl_sched.pdcch_ul) { for (const stack_interface_phy_nr::pdcch_ul_t& pdcch : dl_sched.pdcch_ul) {
// Set PDCCH configuration, including DCI dedicated // Set PDCCH configuration, including DCI dedicated
if (srsran_enb_dl_nr_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error setting DL configuration"); logger.error("PDCCH: Error setting DL configuration");
return false; return false;
} }
// Put PDCCH message // Put PDCCH message
if (srsran_enb_dl_nr_pdcch_put_ul(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_pdcch_put_ul(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error putting DL message"); logger.error("PDCCH: Error putting DL message");
return false; return false;
} }
@ -206,7 +284,7 @@ bool slot_worker::work_dl()
// Log PDCCH information // Log PDCCH information
if (logger.info.enabled()) { if (logger.info.enabled()) {
std::array<char, 512> str = {}; std::array<char, 512> str = {};
srsran_enb_dl_nr_pdcch_ul_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size()); srsran_gnb_dl_pdcch_ul_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size());
logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx); logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
} }
} }
@ -214,7 +292,7 @@ bool slot_worker::work_dl()
// Encode PDSCH // Encode PDSCH
for (stack_interface_phy_nr::pdsch_t& pdsch : dl_sched.pdsch) { for (stack_interface_phy_nr::pdsch_t& pdsch : dl_sched.pdsch) {
// Put PDSCH message // Put PDSCH message
if (srsran_enb_dl_nr_pdsch_put(&gnb_dl, &dl_slot_cfg, &pdsch.sch, pdsch.data.data()) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_pdsch_put(&gnb_dl, &dl_slot_cfg, &pdsch.sch, pdsch.data.data()) < SRSRAN_SUCCESS) {
logger.error("PDSCH: Error putting DL message"); logger.error("PDSCH: Error putting DL message");
return false; return false;
} }
@ -222,7 +300,7 @@ bool slot_worker::work_dl()
// Log PDSCH information // Log PDSCH information
if (logger.info.enabled()) { if (logger.info.enabled()) {
std::array<char, 512> str = {}; std::array<char, 512> str = {};
srsran_enb_dl_nr_pdsch_info(&gnb_dl, &pdsch.sch, str.data(), (uint32_t)str.size()); srsran_gnb_dl_pdsch_info(&gnb_dl, &pdsch.sch, str.data(), (uint32_t)str.size());
logger.info("PDSCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx); logger.info("PDSCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
} }
} }
@ -233,7 +311,7 @@ bool slot_worker::work_dl()
} }
// Generate baseband signal // Generate baseband signal
srsran_enb_dl_nr_gen_signal(&gnb_dl); srsran_gnb_dl_gen_signal(&gnb_dl);
// Add SSB to the baseband signal // Add SSB to the baseband signal
for (const stack_interface_phy_nr::ssb_t& ssb : dl_sched.ssb) { for (const stack_interface_phy_nr::ssb_t& ssb : dl_sched.ssb) {

@ -33,19 +33,27 @@ namespace srsenb {
enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) :
thread("STACK"), thread("STACK"),
mac_logger(srslog::fetch_basic_logger("MAC", log_sink)), mac_logger(srslog::fetch_basic_logger("MAC", log_sink)),
mac_nr_logger(srslog::fetch_basic_logger("MAC-NR", log_sink)),
rlc_logger(srslog::fetch_basic_logger("RLC", log_sink, false)), rlc_logger(srslog::fetch_basic_logger("RLC", log_sink, false)),
rlc_nr_logger(srslog::fetch_basic_logger("RLC-NR", log_sink, false)),
pdcp_logger(srslog::fetch_basic_logger("PDCP", log_sink, false)), pdcp_logger(srslog::fetch_basic_logger("PDCP", log_sink, false)),
pdcp_nr_logger(srslog::fetch_basic_logger("PDCP-NR", log_sink, false)),
rrc_logger(srslog::fetch_basic_logger("RRC", log_sink, false)), rrc_logger(srslog::fetch_basic_logger("RRC", log_sink, false)),
rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", log_sink, false)),
s1ap_logger(srslog::fetch_basic_logger("S1AP", log_sink, false)), s1ap_logger(srslog::fetch_basic_logger("S1AP", log_sink, false)),
gtpu_logger(srslog::fetch_basic_logger("GTPU", log_sink, false)), gtpu_logger(srslog::fetch_basic_logger("GTPU", log_sink, false)),
stack_logger(srslog::fetch_basic_logger("STCK", log_sink, false)), stack_logger(srslog::fetch_basic_logger("STCK", log_sink, false)),
task_sched(512, 128), task_sched(512, 128),
pdcp(&task_sched, pdcp_logger), pdcp(&task_sched, pdcp_logger),
pdcp_nr(&task_sched, pdcp_nr_logger),
mac(&task_sched, mac_logger), mac(&task_sched, mac_logger),
mac_nr(&task_sched),
rlc(rlc_logger), rlc(rlc_logger),
rlc_nr(rlc_nr_logger),
gtpu(&task_sched, gtpu_logger, &rx_sockets), gtpu(&task_sched, gtpu_logger, &rx_sockets),
s1ap(&task_sched, s1ap_logger, &rx_sockets), s1ap(&task_sched, s1ap_logger, &rx_sockets),
rrc(&task_sched), rrc(&task_sched),
rrc_nr(&task_sched),
mac_pcap(), mac_pcap(),
pending_stack_metrics(64) pending_stack_metrics(64)
{ {
@ -87,19 +95,25 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
// setup logging for each layer // setup logging for each layer
mac_logger.set_level(srslog::str_to_basic_level(args.log.mac_level)); mac_logger.set_level(srslog::str_to_basic_level(args.log.mac_level));
mac_logger.set_hex_dump_max_size(args.log.mac_hex_limit); mac_nr_logger.set_level(srslog::str_to_basic_level(args.log.mac_level));
// Init logs
rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level)); rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level));
rlc_nr_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level));
pdcp_logger.set_level(srslog::str_to_basic_level(args.log.pdcp_level)); pdcp_logger.set_level(srslog::str_to_basic_level(args.log.pdcp_level));
pdcp_nr_logger.set_level(srslog::str_to_basic_level(args.log.pdcp_level));
rrc_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level)); rrc_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level));
rrc_nr_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level));
gtpu_logger.set_level(srslog::str_to_basic_level(args.log.gtpu_level)); gtpu_logger.set_level(srslog::str_to_basic_level(args.log.gtpu_level));
s1ap_logger.set_level(srslog::str_to_basic_level(args.log.s1ap_level)); s1ap_logger.set_level(srslog::str_to_basic_level(args.log.s1ap_level));
stack_logger.set_level(srslog::str_to_basic_level(args.log.stack_level)); stack_logger.set_level(srslog::str_to_basic_level(args.log.stack_level));
mac_logger.set_hex_dump_max_size(args.log.mac_hex_limit);
mac_nr_logger.set_hex_dump_max_size(args.log.mac_hex_limit);
rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit); rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit);
rlc_nr_logger.set_hex_dump_max_size(args.log.rlc_hex_limit);
pdcp_logger.set_hex_dump_max_size(args.log.pdcp_hex_limit); pdcp_logger.set_hex_dump_max_size(args.log.pdcp_hex_limit);
pdcp_nr_logger.set_hex_dump_max_size(args.log.pdcp_hex_limit);
rrc_logger.set_hex_dump_max_size(args.log.rrc_hex_limit); rrc_logger.set_hex_dump_max_size(args.log.rrc_hex_limit);
rrc_nr_logger.set_hex_dump_max_size(args.log.rrc_hex_limit);
gtpu_logger.set_hex_dump_max_size(args.log.gtpu_hex_limit); gtpu_logger.set_hex_dump_max_size(args.log.gtpu_hex_limit);
s1ap_logger.set_hex_dump_max_size(args.log.s1ap_hex_limit); s1ap_logger.set_hex_dump_max_size(args.log.s1ap_hex_limit);
stack_logger.set_hex_dump_max_size(args.log.stack_hex_limit); stack_logger.set_hex_dump_max_size(args.log.stack_hex_limit);
@ -133,7 +147,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
} }
rlc.init(&pdcp, &rrc, &mac, task_sched.get_timer_handler()); rlc.init(&pdcp, &rrc, &mac, task_sched.get_timer_handler());
pdcp.init(&rlc, &rrc, &gtpu); pdcp.init(&rlc, &rrc, &gtpu);
if (rrc.init(rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu) != SRSRAN_SUCCESS) { if (rrc.init(rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &rrc_nr) != SRSRAN_SUCCESS) {
stack_logger.error("Couldn't initialize RRC"); stack_logger.error("Couldn't initialize RRC");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }

@ -27,10 +27,10 @@ namespace srsenb {
gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(srslog::fetch_basic_logger("RLC-NR")) gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(srslog::fetch_basic_logger("RLC-NR"))
{ {
m_mac.reset(new mac_nr()); m_mac.reset(new mac_nr(&task_sched));
m_rlc.reset(new rlc_nr("RLC-NR")); m_rlc.reset(new rlc_nr("RLC-NR"));
m_pdcp.reset(new pdcp_nr(&task_sched, "PDCP-NR")); m_pdcp.reset(new pdcp_nr(&task_sched, "PDCP-NR"));
m_rrc.reset(new rrc_nr(task_sched.get_timer_handler())); m_rrc.reset(new rrc_nr(&task_sched));
m_sdap.reset(new sdap()); m_sdap.reset(new sdap());
m_gw.reset(new srsue::gw()); m_gw.reset(new srsue::gw());
// m_gtpu.reset(new srsenb::gtpu()); // m_gtpu.reset(new srsenb::gtpu());
@ -88,7 +88,7 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr
pdcp_args.log_hex_limit = args.log.pdcp_hex_limit; pdcp_args.log_hex_limit = args.log.pdcp_hex_limit;
m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get()); m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get());
m_rrc->init(rrc_cfg_, phy, m_mac.get(), m_rlc.get(), m_pdcp.get(), nullptr, nullptr); m_rrc->init(rrc_cfg_, phy, m_mac.get(), m_rlc.get(), m_pdcp.get(), nullptr, nullptr, nullptr);
m_sdap->init(m_pdcp.get(), nullptr, m_gw.get()); m_sdap->init(m_pdcp.get(), nullptr, m_gw.get());
@ -198,5 +198,13 @@ int gnb_stack_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul
{ {
return m_mac->get_ul_sched(slot_cfg, ul_sched); return m_mac->get_ul_sched(slot_cfg, ul_sched);
} }
int gnb_stack_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info)
{
return m_mac->pucch_info(slot_cfg, pucch_info);
}
int gnb_stack_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info)
{
return m_mac->pusch_info(slot_cfg, pusch_info);
}
} // namespace srsenb } // namespace srsenb

@ -29,7 +29,9 @@
namespace srsenb { namespace srsenb {
mac_nr::mac_nr() : logger(srslog::fetch_basic_logger("MAC-NR")) {} mac_nr::mac_nr(srsran::task_sched_handle task_sched_) :
logger(srslog::fetch_basic_logger("MAC-NR")), task_sched(task_sched_)
{}
mac_nr::~mac_nr() mac_nr::~mac_nr()
{ {
@ -285,5 +287,13 @@ int mac_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched
{ {
return 0; return 0;
} }
int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info)
{
return 0;
}
int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info)
{
return 0;
}
} // namespace srsenb } // namespace srsenb

@ -605,9 +605,13 @@ uint8_t* ue::generate_mch_pdu(uint32_t harq_pid,
/******* METRICS interface ***************/ /******* METRICS interface ***************/
void ue::metrics_read(mac_ue_metrics_t* metrics_) void ue::metrics_read(mac_ue_metrics_t* metrics_)
{ {
uint32_t ul_buffer = sched->get_ul_buffer(rnti);
uint32_t dl_buffer = sched->get_dl_buffer(rnti);
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.rnti = rnti; ue_metrics.rnti = rnti;
ue_metrics.ul_buffer = sched->get_ul_buffer(rnti); ue_metrics.ul_buffer = ul_buffer;
ue_metrics.dl_buffer = sched->get_dl_buffer(rnti); ue_metrics.dl_buffer = dl_buffer;
// set PCell sector id // set PCell sector id
std::array<int, SRSRAN_MAX_CARRIERS> cc_list = sched->get_enb_ue_cc_map(rnti); std::array<int, SRSRAN_MAX_CARRIERS> cc_list = sched->get_enb_ue_cc_map(rnti);
@ -623,12 +627,14 @@ void ue::metrics_read(mac_ue_metrics_t* metrics_)
void ue::metrics_phr(float phr) void ue::metrics_phr(float phr)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.phr = SRSRAN_VEC_CMA(phr, ue_metrics.phr, phr_counter); ue_metrics.phr = SRSRAN_VEC_CMA(phr, ue_metrics.phr, phr_counter);
phr_counter++; phr_counter++;
} }
void ue::metrics_dl_ri(uint32_t dl_ri) void ue::metrics_dl_ri(uint32_t dl_ri)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
if (ue_metrics.dl_ri == 0.0f) { if (ue_metrics.dl_ri == 0.0f) {
ue_metrics.dl_ri = (float)dl_ri + 1.0f; ue_metrics.dl_ri = (float)dl_ri + 1.0f;
} else { } else {
@ -639,18 +645,21 @@ void ue::metrics_dl_ri(uint32_t dl_ri)
void ue::metrics_dl_pmi(uint32_t dl_ri) void ue::metrics_dl_pmi(uint32_t dl_ri)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.dl_pmi = SRSRAN_VEC_CMA((float)dl_ri, ue_metrics.dl_pmi, dl_pmi_counter); ue_metrics.dl_pmi = SRSRAN_VEC_CMA((float)dl_ri, ue_metrics.dl_pmi, dl_pmi_counter);
dl_pmi_counter++; dl_pmi_counter++;
} }
void ue::metrics_dl_cqi(uint32_t dl_cqi) void ue::metrics_dl_cqi(uint32_t dl_cqi)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.dl_cqi = SRSRAN_VEC_CMA((float)dl_cqi, ue_metrics.dl_cqi, dl_cqi_counter); ue_metrics.dl_cqi = SRSRAN_VEC_CMA((float)dl_cqi, ue_metrics.dl_cqi, dl_cqi_counter);
dl_cqi_counter++; dl_cqi_counter++;
} }
void ue::metrics_rx(bool crc, uint32_t tbs) void ue::metrics_rx(bool crc, uint32_t tbs)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
if (crc) { if (crc) {
ue_metrics.rx_brate += tbs * 8; ue_metrics.rx_brate += tbs * 8;
} else { } else {
@ -661,6 +670,7 @@ void ue::metrics_rx(bool crc, uint32_t tbs)
void ue::metrics_tx(bool crc, uint32_t tbs) void ue::metrics_tx(bool crc, uint32_t tbs)
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
if (crc) { if (crc) {
ue_metrics.tx_brate += tbs * 8; ue_metrics.tx_brate += tbs * 8;
} else { } else {
@ -671,6 +681,7 @@ void ue::metrics_tx(bool crc, uint32_t tbs)
void ue::metrics_cnt() void ue::metrics_cnt()
{ {
std::lock_guard<std::mutex> lock(metrics_mutex);
ue_metrics.nof_tti++; ue_metrics.nof_tti++;
} }

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
set(SOURCES rrc.cc rrc_ue.cc rrc_mobility.cc rrc_cell_cfg.cc rrc_bearer_cfg.cc mac_controller.cc ue_rr_cfg.cc ue_meas_cfg.cc) set(SOURCES rrc.cc rrc_ue.cc rrc_mobility.cc rrc_cell_cfg.cc rrc_bearer_cfg.cc mac_controller.cc ue_rr_cfg.cc ue_meas_cfg.cc rrc_endc.cc)
add_library(srsenb_rrc STATIC ${SOURCES}) add_library(srsenb_rrc STATIC ${SOURCES})
set(SOURCES rrc_nr.cc) set(SOURCES rrc_nr.cc)

@ -21,6 +21,7 @@
#include "srsenb/hdr/stack/rrc/rrc.h" #include "srsenb/hdr/stack/rrc/rrc.h"
#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h"
#include "srsenb/hdr/stack/rrc/rrc_endc.h"
#include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/hdr/stack/rrc/rrc_paging.h" #include "srsenb/hdr/stack/rrc/rrc_paging.h"
#include "srsenb/hdr/stack/s1ap/s1ap.h" #include "srsenb/hdr/stack/s1ap/s1ap.h"
@ -54,12 +55,25 @@ int32_t rrc::init(const rrc_cfg_t& cfg_,
s1ap_interface_rrc* s1ap_, s1ap_interface_rrc* s1ap_,
gtpu_interface_rrc* gtpu_) gtpu_interface_rrc* gtpu_)
{ {
phy = phy_; return init(cfg_, phy_, mac_, rlc_, pdcp_, s1ap_, gtpu_, nullptr);
mac = mac_; }
rlc = rlc_;
pdcp = pdcp_; int32_t rrc::init(const rrc_cfg_t& cfg_,
gtpu = gtpu_; phy_interface_rrc_lte* phy_,
s1ap = s1ap_; mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_,
pdcp_interface_rrc* pdcp_,
s1ap_interface_rrc* s1ap_,
gtpu_interface_rrc* gtpu_,
rrc_nr_interface_rrc* rrc_nr_)
{
phy = phy_;
mac = mac_;
rlc = rlc_;
pdcp = pdcp_;
gtpu = gtpu_;
s1ap = s1ap_;
rrc_nr = rrc_nr_;
cfg = cfg_; cfg = cfg_;
@ -537,6 +551,22 @@ void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_st
ue_it->second->mobility_handler->trigger(erabs); ue_it->second->mobility_handler->trigger(erabs);
} }
/*******************************************************************************
EN-DC/NSA helper functions
*******************************************************************************/
void rrc::sgnb_addition_ack(uint16_t rnti,
const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
{
users.at(rnti)->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15);
}
void rrc::sgnb_addition_reject(uint16_t rnti)
{
users.at(rnti)->endc_handler->handle_sgnb_addition_reject();
}
/******************************************************************************* /*******************************************************************************
Private functions Private functions
All private functions are not mutexed and must be called from a mutexed environment All private functions are not mutexed and must be called from a mutexed environment

@ -0,0 +1,252 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsenb/hdr/stack/rrc/rrc_endc.h"
namespace srsenb {
#define Info(fmt, ...) logger.info("ENDC: " fmt, ##__VA_ARGS__)
#define Error(fmt, ...) logger.error("ENDC: " fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) logger.warning("ENDC: " fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) logger.debug("ENDC: " fmt, ##__VA_ARGS__)
#define procInfo(fmt, ...) parent->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procWarning(fmt, ...) parent->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procError(fmt, ...) parent->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
using namespace asn1::rrc;
/*************************************************************************************************
* rrc_endc class
************************************************************************************************/
rrc::ue::rrc_endc::rrc_endc(rrc::ue* outer_ue) :
base_t(outer_ue->parent->logger), rrc_ue(outer_ue), rrc_enb(outer_ue->parent), logger(outer_ue->parent->logger)
{}
//! Method to add NR fields to a RRC Connection Reconfiguration Message
bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg)
{
if (not endc_supported) {
// skipping ENDC-related field
return false;
}
if (not is_endc_activation_running()) {
// add hard-coded measConfig
conn_recfg->meas_cfg_present = true;
meas_cfg_s& meas_cfg = conn_recfg->meas_cfg;
meas_cfg.meas_obj_to_add_mod_list_present = true;
meas_cfg.meas_obj_to_add_mod_list.resize(2);
auto& meas_obj = meas_cfg.meas_obj_to_add_mod_list[0];
meas_obj.meas_obj_id = 1;
meas_obj.meas_obj.set_meas_obj_eutra();
meas_obj.meas_obj.meas_obj_eutra().carrier_freq = 300;
meas_obj.meas_obj.meas_obj_eutra().allowed_meas_bw = allowed_meas_bw_opts::mbw50;
meas_obj.meas_obj.meas_obj_eutra().presence_ant_port1 = false;
meas_obj.meas_obj.meas_obj_eutra().neigh_cell_cfg.from_number(0b01);
auto& meas_obj2 = meas_cfg.meas_obj_to_add_mod_list[1];
meas_obj2.meas_obj_id = 2;
meas_obj2.meas_obj.set_meas_obj_nr_r15();
meas_obj2.meas_obj.meas_obj_nr_r15().carrier_freq_r15 = 634176;
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.meas_timing_cfg_r15.periodicity_and_offset_r15.set_sf20_r15();
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.meas_timing_cfg_r15.ssb_dur_r15 =
asn1::rrc::mtc_ssb_nr_r15_s::ssb_dur_r15_opts::sf1;
meas_obj2.meas_obj.meas_obj_nr_r15().rs_cfg_ssb_r15.subcarrier_spacing_ssb_r15 =
asn1::rrc::rs_cfg_ssb_nr_r15_s::subcarrier_spacing_ssb_r15_opts::khz30;
meas_obj2.meas_obj.meas_obj_nr_r15().ext = true;
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.set_present(true);
meas_obj2.meas_obj.meas_obj_nr_r15().band_nr_r15.get()->set_setup() = 78;
// report config
meas_cfg.report_cfg_to_add_mod_list_present = true;
meas_cfg.report_cfg_to_add_mod_list.resize(1);
auto& report_cfg = meas_cfg.report_cfg_to_add_mod_list[0];
report_cfg.report_cfg_id = 1;
report_cfg.report_cfg.set_report_cfg_inter_rat();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.set_event();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.set_event_b1_nr_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.set_nr_rsrp_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.nr_rsrp_r15() = 56;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.event_b1_nr_r15().report_on_leave_r15 =
false;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().hysteresis = 0;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().time_to_trigger = time_to_trigger_opts::ms100;
report_cfg.report_cfg.report_cfg_inter_rat().max_report_cells = 1;
report_cfg.report_cfg.report_cfg_inter_rat().report_interv = report_interv_opts::ms120;
report_cfg.report_cfg.report_cfg_inter_rat().report_amount = report_cfg_inter_rat_s::report_amount_opts::r1;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.set_present(true);
report_cfg.report_cfg.report_cfg_inter_rat().ext = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrp = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrq = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_sinr = true;
// measIdToAddModList
meas_cfg.meas_id_to_add_mod_list_present = true;
meas_cfg.meas_id_to_add_mod_list.resize(1);
auto& meas_id = meas_cfg.meas_id_to_add_mod_list[0];
meas_id.meas_id = 1;
meas_id.meas_obj_id = 2;
meas_id.report_cfg_id = 1;
// quantityConfig
meas_cfg.quant_cfg_present = true;
meas_cfg.quant_cfg.quant_cfg_eutra_present = true;
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.set_present(true);
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()->resize(1);
meas_cfg.quant_cfg.ext = true;
auto& meas_quant = meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()[0];
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15_present = true;
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15 = filt_coef_opts::fc3;
// measGapConfig
meas_cfg.meas_gap_cfg_present = true;
meas_cfg.meas_gap_cfg.set_setup();
meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16;
} else {
// only add reconfigure EN-DC extension/release 15.10 field if ENDC activation is active
conn_recfg->non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present =
true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present = true;
rrc_conn_recfg_v1510_ies_s& reconf_v1510 = conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
reconf_v1510.nr_cfg_r15_present = true;
reconf_v1510.sk_counter_r15_present = true;
reconf_v1510.sk_counter_r15 = 0;
}
return true;
}
//! Called when UE capabilities are received
void rrc::ue::rrc_endc::handle_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps)
{
// Only enabled ENDC support if UE caps have been exchanged and UE signals support
if (eutra_caps.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
auto& ue_cap_v1170 =
eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1170.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext_present) {
auto& ue_cap_v1330 = ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1330.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present) {
auto& ue_cap_v1510 = ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1510.irat_params_nr_r15_present) {
if (ue_cap_v1510.irat_params_nr_r15.en_dc_r15_present) {
logger.info("Enabling ENDC support for rnti=%d", rrc_ue->rnti);
endc_supported = true;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
//! Method called whenever the eNB receives a MeasReport from the UE
void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg)
{
// Ignore event if ENDC isn't supported
if (not endc_supported) {
return;
}
if (not is_in_state<idle_st>()) {
Info("Received a MeasReport while already enabling ENDC support. Ignoring...");
return;
}
// Check if meas_id is valid
const meas_results_s& meas_res = msg.crit_exts.c1().meas_report_r8().meas_results;
if (not meas_res.meas_result_neigh_cells_present) {
Info("Received a MeasReport, but the UE did not detect any cell.");
return;
}
// only handle NR cells here, EUTRA is handled in mobility class
if (meas_res.meas_result_neigh_cells.type().value !=
meas_results_s::meas_result_neigh_cells_c_::types::meas_result_neigh_cell_list_nr_r15) {
return;
}
// Start EN-DC activation
logger.info("Triggering SgNB addition");
rrc_enb->rrc_nr->sgnb_addition_request(rrc_ue->rnti);
sgnb_add_req_sent_ev sgnb_add_req{};
trigger(sgnb_add_req);
}
void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
{
logger.info("Received SgNB addition acknowledgement for rnti=%d", rrc_ue->rnti);
// prepare reconfiguration message with NR fields
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
return;
}
// rrc_enb->send_connection_reconf(std::move(pdu));
}
void rrc::ue::rrc_endc::handle_sgnb_addition_reject()
{
logger.error("Received SgNB addition reject for rnti=%d", rrc_ue->rnti);
}
void rrc::ue::rrc_endc::handle_recfg_complete(wait_recfg_comp& s, const recfg_complete_ev& ev)
{
logger.info("User rnti=0x%x successfully enabled EN-DC", rrc_ue->rnti);
}
} // namespace srsenb

@ -28,15 +28,18 @@ using namespace asn1::rrc_nr;
namespace srsenb { namespace srsenb {
rrc_nr::rrc_nr(srsran::timer_handler* timers_) : logger(srslog::fetch_basic_logger("RRC-NR")), timers(timers_) {} rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) :
logger(srslog::fetch_basic_logger("RRC-NR")), task_sched(task_sched_)
int rrc_nr::init(const rrc_nr_cfg_t& cfg_, {}
phy_interface_stack_nr* phy_,
mac_interface_rrc_nr* mac_, int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
rlc_interface_rrc_nr* rlc_, phy_interface_stack_nr* phy_,
pdcp_interface_rrc_nr* pdcp_, mac_interface_rrc_nr* mac_,
ngap_interface_rrc_nr* ngap_, rlc_interface_rrc_nr* rlc_,
gtpu_interface_rrc_nr* gtpu_) pdcp_interface_rrc_nr* pdcp_,
ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu_,
rrc_eutra_interface_rrc_nr* rrc_eutra_)
{ {
phy = phy_; phy = phy_;
mac = mac_; mac = mac_;
@ -357,6 +360,23 @@ void rrc_nr::write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_
void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {} void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {}
/*******************************************************************************
Interface for EUTRA RRC
*******************************************************************************/
int rrc_nr::sgnb_addition_request(uint16_t rnti)
{
// try to allocate new user
task_sched.defer_task([]() {});
// return straight away
return SRSRAN_SUCCESS;
}
int rrc_nr::sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response)
{
return SRSRAN_SUCCESS;
}
/******************************************************************************* /*******************************************************************************
UE class UE class
@ -366,7 +386,7 @@ void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {}
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_) rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_)
{ {
// setup periodic RRCSetup send // setup periodic RRCSetup send
rrc_setup_periodic_timer = parent->timers->get_unique_timer(); rrc_setup_periodic_timer = parent->task_sched.get_unique_timer();
rrc_setup_periodic_timer.set(5000, [this](uint32_t tid) { rrc_setup_periodic_timer.set(5000, [this](uint32_t tid) {
send_connection_setup(); send_connection_setup();
rrc_setup_periodic_timer.run(); rrc_setup_periodic_timer.run();
@ -416,4 +436,27 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)
parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu)); parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu));
} }
int rrc_nr::ue::handle_sgnb_addition_request()
{
// provide hard-coded NR configs
asn1::dyn_octstring nr_config;
rrc_recfg_s reconfig;
reconfig.rrc_transaction_id = ((transaction_id++) % 4u);
rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.set_rrc_recfg();
recfg_ies.radio_bearer_cfg_present = true;
recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true;
recfg_ies.radio_bearer_cfg.drb_to_release_list.resize(1);
// recfg_ies.radio_bearer_cfg.drb_to_release_list[0].set_eps_bearer_id(5);
// TODO: fill configs
asn1::dyn_octstring nr_secondary_cell_group_cfg;
asn1::dyn_octstring nr_radio_bearer_config;
parent->rrc_eutra->sgnb_addition_ack(rnti, nr_secondary_cell_group_cfg, nr_radio_bearer_config);
return SRSRAN_SUCCESS;
}
} // namespace srsenb } // namespace srsenb

@ -22,6 +22,7 @@
#include "srsenb/hdr/stack/rrc/rrc_ue.h" #include "srsenb/hdr/stack/rrc/rrc_ue.h"
#include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/common/common_enb.h"
#include "srsenb/hdr/stack/rrc/mac_controller.h" #include "srsenb/hdr/stack/rrc/mac_controller.h"
#include "srsenb/hdr/stack/rrc/rrc_endc.h"
#include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h" #include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
@ -87,6 +88,10 @@ int rrc::ue::init()
} }
mobility_handler = make_rnti_obj<rrc_mobility>(rnti, this); mobility_handler = make_rnti_obj<rrc_mobility>(rnti, this);
if (parent->rrc_nr != nullptr) {
endc_handler = make_rnti_obj<rrc_endc>(rnti, this);
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -382,6 +387,9 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu)
} else { } else {
parent->logger.warning("Received MeasReport but no mobility configuration is available"); parent->logger.warning("Received MeasReport but no mobility configuration is available");
} }
if (endc_handler) {
endc_handler->handle_ue_meas_report(ul_dcch_msg.msg.c1().meas_report());
}
break; break;
case ul_dcch_msg_type_c::c1_c_::types::ue_info_resp_r9: case ul_dcch_msg_type_c::c1_c_::types::ue_info_resp_r9:
handle_ue_info_resp(ul_dcch_msg.msg.c1().ue_info_resp_r9(), std::move(original_pdu)); handle_ue_info_resp(ul_dcch_msg.msg.c1().ue_info_resp_r9(), std::move(original_pdu));
@ -794,6 +802,10 @@ void rrc::ue::send_connection_reconf(srsran::unique_byte_buffer_t pdu,
} }
} }
if (endc_handler != nullptr) {
endc_handler->fill_conn_recfg(&recfg_r8);
}
// Reuse same PDU // Reuse same PDU
if (pdu != nullptr) { if (pdu != nullptr) {
pdu->clear(); pdu->clear();
@ -947,6 +959,10 @@ bool rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg)
ue_capabilities = srsran::make_rrc_ue_capabilities(eutra_capabilities); ue_capabilities = srsran::make_rrc_ue_capabilities(eutra_capabilities);
parent->logger.info("UE rnti: 0x%x category: %d", rnti, eutra_capabilities.ue_category); parent->logger.info("UE rnti: 0x%x category: %d", rnti, eutra_capabilities.ue_category);
if (endc_handler) {
endc_handler->handle_ue_capabilities(eutra_capabilities);
}
} }
if (eutra_capabilities_unpacked) { if (eutra_capabilities_unpacked) {
@ -1150,6 +1166,18 @@ void rrc::ue::update_scells()
parent->logger.info("SCells activated for rnti=0x%x", rnti); parent->logger.info("SCells activated for rnti=0x%x", rnti);
} }
/// EN-DC helper
void rrc::ue::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15,
const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15)
{
endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15);
}
void rrc::ue::handle_sgnb_addition_reject()
{
endc_handler->handle_sgnb_addition_reject();
}
/********************** HELPERS ***************************/ /********************** HELPERS ***************************/
void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg, std::string* octet_str) void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg, std::string* octet_str)

@ -20,7 +20,7 @@
*/ */
#include "sched_nr_sim_ue.h" #include "sched_nr_sim_ue.h"
#include "lib/include/srsran/common/test_common.h" #include "srsran/common/test_common.h"
namespace srsenb { namespace srsenb {

@ -192,10 +192,10 @@ int test_s1ap_mobility(srsran::log_sink_spy& spy, test_event test_params)
/* Receive MeasReport from UE (correct if PCI=2) */ /* Receive MeasReport from UE (correct if PCI=2) */
if (test_params == test_event::wrong_measreport) { if (test_params == test_event::wrong_measreport) {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
} else { } else {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
} }
tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu)); tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu));
tester.tic(); tester.tic();
@ -212,7 +212,7 @@ int test_s1ap_mobility(srsran::log_sink_spy& spy, test_event test_params)
if (test_params == test_event::concurrent_ho) { if (test_params == test_event::concurrent_ho) {
s1ap.last_ho_required = {}; s1ap.last_ho_required = {};
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu)); tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu));
tester.tic(); tester.tic();
TESTASSERT(s1ap.last_ho_required.rrc_container == nullptr); TESTASSERT(s1ap.last_ho_required.rrc_container == nullptr);
@ -250,7 +250,7 @@ int test_s1ap_mobility(srsran::log_sink_spy& spy, test_event test_params)
0x01, 0x48, 0x04, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0xa0, 0x07, 0xa0, 0x01, 0x48, 0x04, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0xa0, 0x07, 0xa0,
0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0xa7, 0xd0, 0xc1, 0xf6, 0xaf, 0x3e, 0x12, 0xcc, 0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0xa7, 0xd0, 0xc1, 0xf6, 0xaf, 0x3e, 0x12, 0xcc,
0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20}; 0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20};
test_helpers::copy_msg_to_buffer(pdu, ho_cmd_rrc_container); copy_msg_to_buffer(pdu, ho_cmd_rrc_container);
TESTASSERT(s1ap.last_enb_status.rnti != tester.rnti); TESTASSERT(s1ap.last_enb_status.rnti != tester.rnti);
tester.rrc.ho_preparation_complete(tester.rnti, rrc::ho_prep_result::success, asn1::s1ap::ho_cmd_s{}, std::move(pdu)); tester.rrc.ho_preparation_complete(tester.rnti, rrc::ho_prep_result::success, asn1::s1ap::ho_cmd_s{}, std::move(pdu));
TESTASSERT(s1ap.last_enb_status.status_present); TESTASSERT(s1ap.last_enb_status.status_present);
@ -390,7 +390,7 @@ int test_s1ap_tenb_mobility(test_event test_params)
tester.rrc.upd_user(0x47, 0x46); tester.rrc.upd_user(0x47, 0x46);
uint8_t recfg_complete[] = {0x10, 0x00}; uint8_t recfg_complete[] = {0x10, 0x00};
test_helpers::copy_msg_to_buffer(pdu, recfg_complete); copy_msg_to_buffer(pdu, recfg_complete);
tester.rrc.write_pdu(0x46, srb_to_lcid(lte_srb::srb1), std::move(pdu)); tester.rrc.write_pdu(0x46, srb_to_lcid(lte_srb::srb1), std::move(pdu));
tester.tic(); tester.tic();
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == sched_interface::ue_bearer_cfg_t::BOTH); TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == sched_interface::ue_bearer_cfg_t::BOTH);
@ -430,10 +430,10 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
/* Receive MeasReport from UE (correct if PCI=2) */ /* Receive MeasReport from UE (correct if PCI=2) */
if (test_params == test_event::wrong_measreport) { if (test_params == test_event::wrong_measreport) {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
} else { } else {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
} }
tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu)); tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu));
tester.tic(); tester.tic();
@ -453,7 +453,7 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
if (test_params == test_event::concurrent_ho) { if (test_params == test_event::concurrent_ho) {
tester.pdcp.last_sdu = {}; tester.pdcp.last_sdu = {};
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu)); tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu));
tester.tic(); tester.tic();
TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr); TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
@ -512,7 +512,7 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
/* Test Case: Terminate first Handover. No extra messages should be sent DL. SR/CQI resources match recfg message */ /* Test Case: Terminate first Handover. No extra messages should be sent DL. SR/CQI resources match recfg message */
uint8_t recfg_complete[] = {0x10, 0x00}; uint8_t recfg_complete[] = {0x10, 0x00};
test_helpers::copy_msg_to_buffer(pdu, recfg_complete); copy_msg_to_buffer(pdu, recfg_complete);
tester.rrc.write_pdu(tester.rnti, srb_to_lcid(lte_srb::srb2), std::move(pdu)); tester.rrc.write_pdu(tester.rnti, srb_to_lcid(lte_srb::srb2), std::move(pdu));
TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr); TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
ue_cfg = &tester.mac.ue_db[tester.rnti]; ue_cfg = &tester.mac.ue_db[tester.rnti];
@ -525,7 +525,7 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
/* Test Case: The RRC should be able to start a new handover */ /* 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 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x05, 0xBC, 0x80}; // PCI == 1
test_helpers::copy_msg_to_buffer(pdu, meas_report); copy_msg_to_buffer(pdu, meas_report);
tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu)); tester.rrc.write_pdu(tester.rnti, 1, std::move(pdu));
tester.tic(); tester.tic();
TESTASSERT(tester.s1ap.last_ho_required.rrc_container == nullptr); TESTASSERT(tester.s1ap.last_ho_required.rrc_container == nullptr);

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

Loading…
Cancel
Save