Merge branch 'next' into agpl_next

# Conflicts:
#	srsue/test/mac_nr/mac_nr_test.cc
master
Codebot 4 years ago committed by Your Name
commit c0282856d0

@ -83,6 +83,7 @@ option(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF)
option(ENABLE_GCOV "Enable gcc/clang address sanitizer" OFF)
option(ENABLE_MSAN "Enable clang memory sanitizer" OFF)
option(ENABLE_TSAN "Enable clang thread sanitizer" OFF)
option(ENABLE_TIDY "Enable clang tidy" OFF)
option(USE_LTE_RATES "Use standard LTE sampling rates" OFF)
@ -479,15 +480,20 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
endif(NOT WIN32)
endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if (ENABLE_ASAN AND ENABLE_MSAN)
message(FATAL_ERROR "ASAN and MSAN cannot be enabled at the same time.")
endif (ENABLE_ASAN AND ENABLE_MSAN)
if ((ENABLE_ASAN AND ENABLE_MSAN) OR (ENABLE_ASAN AND ENABLE_TSAN) OR (ENABLE_MSAN AND ENABLE_TSAN))
message(FATAL_ERROR "ASAN, MSAN and TSAN cannot be enabled at the same time.")
endif ()
if (ENABLE_ASAN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
endif (ENABLE_ASAN)
if (ENABLE_TSAN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
endif (ENABLE_TSAN)
if (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie")

@ -24,6 +24,7 @@
#include "srsran/adt/detail/type_storage.h"
#include "srsran/adt/expected.h"
#include "srsran/adt/pool/pool_utils.h"
#include "srsran/common/srsran_assert.h"
#include <array>
@ -240,14 +241,6 @@ protected:
size_t count = 0;
};
struct noop_operator {
template <typename T>
void operator()(const T&)
{
// noop
}
};
/**
* Base common class for definition of blocking queue data structures with the following features:
* - it stores pushed/popped samples in an internal circular buffer
@ -267,15 +260,18 @@ public:
base_blocking_queue(PushingFunc push_func_, PoppingFunc pop_func_, Args&&... args) :
circ_buffer(std::forward<Args>(args)...), push_func(push_func_), pop_func(pop_func_)
{}
base_blocking_queue(const base_blocking_queue&) = delete;
base_blocking_queue(base_blocking_queue&&) = delete;
base_blocking_queue& operator=(const base_blocking_queue&) = delete;
base_blocking_queue& operator=(base_blocking_queue&&) = delete;
void stop()
{
std::unique_lock<std::mutex> lock(mutex);
if (active) {
active = false;
if (nof_waiting == 0) {
return;
}
if (nof_waiting > 0) {
// Stop pending pushing/popping threads
do {
lock.unlock();
cvar_empty.notify_all();
@ -284,6 +280,10 @@ public:
lock.lock();
} while (nof_waiting > 0);
}
// Empty queue
circ_buffer.clear();
}
}
bool try_push(const T& t) { return push_(t, false); }
@ -300,7 +300,6 @@ public:
bool pop_wait_until(T& obj, const std::chrono::system_clock::time_point& until) { return pop_(obj, true, &until); }
void clear()
{
std::lock_guard<std::mutex> lock(mutex);
T obj;
while (pop_(obj, false)) {
}

@ -179,6 +179,16 @@ public:
return iterator(this, idx);
}
template <typename U>
void overwrite(K id, U&& obj)
{
size_t idx = id % N;
if (present[idx]) {
erase(buffer[idx].get().first);
}
insert(id, std::forward<U>(obj));
}
bool erase(K id)
{
if (not contains(id)) {
@ -193,20 +203,24 @@ public:
iterator erase(iterator it)
{
srsran_assert(it.idx < N, "Iterator out-of-bounds (%zd >= %zd)", it.idx, N);
srsran_assert(it.idx < N and it.ptr == this, "Iterator out-of-bounds (%zd >= %zd)", it.idx, N);
iterator next = it;
++next;
it->~obj_t();
present[it->first] = false;
present[it.idx] = false;
get_obj_(it.idx).~obj_t();
--count;
return next;
}
void clear()
{
for (auto it = begin(); it != end();) {
it = erase(it);
for (size_t i = 0; i < N; ++i) {
if (present[i]) {
present[i] = false;
get_obj_(i).~obj_t();
}
}
count = 0;
}
T& operator[](K id)

@ -22,6 +22,7 @@
#ifndef SRSRAN_TYPE_STORAGE_H
#define SRSRAN_TYPE_STORAGE_H
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <utility>
@ -40,8 +41,9 @@ union max_alignment_t {
long double d2;
uint32_t* ptr;
};
const static size_t max_alignment = alignof(max_alignment_t);
template <typename T>
template <typename T, size_t MinSize = 0, size_t AlignSize = 0>
struct type_storage {
using value_type = T;
@ -51,19 +53,29 @@ struct type_storage {
new (&buffer) T(std::forward<Args>(args)...);
}
void destroy() { get().~T(); }
void copy_ctor(const type_storage<T>& other) { emplace(other.get()); }
void move_ctor(type_storage<T>&& other) { emplace(std::move(other.get())); }
void copy_assign(const type_storage<T>& other) { get() = other.get(); }
void move_assign(type_storage<T>&& other) { get() = std::move(other.get()); }
void copy_ctor(const type_storage& other) { emplace(other.get()); }
void move_ctor(type_storage&& other) { emplace(std::move(other.get())); }
void copy_assign(const type_storage& other) { get() = other.get(); }
void move_assign(type_storage&& other) { get() = std::move(other.get()); }
T& get() { return reinterpret_cast<T&>(buffer); }
const T& get() const { return reinterpret_cast<const T&>(buffer); }
typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer;
void* addr() { return static_cast<void*>(&buffer); }
const void* addr() const { return static_cast<void*>(&buffer); }
explicit operator void*() { return addr(); }
const static size_t obj_size = sizeof(T) > MinSize ? sizeof(T) : MinSize;
const static size_t align_size = alignof(T) > AlignSize ? alignof(T) : AlignSize;
typename std::aligned_storage<obj_size, align_size>::type buffer;
};
template <typename T>
void copy_if_present_helper(type_storage<T>& lhs, const type_storage<T>& rhs, bool lhs_present, bool rhs_present)
template <typename T, size_t MinSize, size_t AlignSize>
void copy_if_present_helper(type_storage<T, MinSize, AlignSize>& lhs,
const type_storage<T, MinSize, AlignSize>& rhs,
bool lhs_present,
bool rhs_present)
{
if (lhs_present and rhs_present) {
lhs.get() = rhs.get();
@ -76,8 +88,11 @@ void copy_if_present_helper(type_storage<T>& lhs, const type_storage<T>& rhs, bo
}
}
template <typename T>
void move_if_present_helper(type_storage<T>& lhs, type_storage<T>& rhs, bool lhs_present, bool rhs_present)
template <typename T, size_t MinSize, size_t AlignSize>
void move_if_present_helper(type_storage<T, MinSize, AlignSize>& lhs,
type_storage<T, MinSize, AlignSize>& rhs,
bool lhs_present,
bool rhs_present)
{
if (lhs_present and rhs_present) {
lhs.move_assign(std::move(rhs));

@ -42,9 +42,9 @@
namespace srsran {
//! Size of the buffer used by "move_callback<R(Args...)>" to store functors without calling "new"
constexpr size_t default_buffer_size = 32;
constexpr size_t default_move_callback_buffer_size = 32;
template <class Signature, size_t Capacity = default_buffer_size>
template <class Signature, size_t Capacity = default_move_callback_buffer_size, bool ForbidAlloc = false>
class move_callback;
namespace task_details {
@ -55,7 +55,7 @@ class oper_table_t
{
public:
constexpr oper_table_t() = default;
virtual R call(void* src, Args&&... args) const = 0;
virtual R call(void* src, Args... args) const = 0;
virtual void move(void* src, void* dest) const = 0;
virtual void dtor(void* src) const = 0;
virtual bool is_in_small_buffer() const = 0;
@ -67,7 +67,7 @@ class empty_table_t : public oper_table_t<R, Args...>
{
public:
constexpr empty_table_t() = default;
R call(void* src, Args&&... args) const final
R call(void* src, Args... args) const final
{
srsran_terminate("ERROR: bad function call (cause: function ptr is empty)");
}
@ -82,7 +82,7 @@ class smallbuffer_table_t : public oper_table_t<R, Args...>
{
public:
constexpr smallbuffer_table_t() = default;
R call(void* src, Args&&... args) const final { return (*static_cast<FunT*>(src))(std::forward<Args>(args)...); }
R call(void* src, Args... args) const final { return (*static_cast<FunT*>(src))(std::forward<Args>(args)...); }
void move(void* src, void* dest) const final
{
::new (dest) FunT(std::move(*static_cast<FunT*>(src)));
@ -98,7 +98,7 @@ class heap_table_t : public oper_table_t<R, Args...>
{
public:
constexpr heap_table_t() = default;
R call(void* src, Args&&... args) const final { return (**static_cast<FunT**>(src))(std::forward<Args>(args)...); }
R call(void* src, Args... args) const final { return (**static_cast<FunT**>(src))(std::forward<Args>(args)...); }
void move(void* src, void* dest) const final
{
*static_cast<FunT**>(dest) = *static_cast<FunT**>(src);
@ -124,8 +124,8 @@ using enable_if_big_capture =
} // namespace task_details
template <class R, class... Args, size_t Capacity>
class move_callback<R(Args...), Capacity>
template <class R, class... Args, size_t Capacity, bool ForbidAlloc>
class move_callback<R(Args...), Capacity, ForbidAlloc>
{
static constexpr size_t capacity = Capacity >= sizeof(void*) ? Capacity : sizeof(void*); ///< size of buffer
using storage_t = typename std::aligned_storage<capacity, alignof(detail::max_alignment_t)>::type;
@ -149,6 +149,9 @@ public:
template <typename T, task_details::enable_if_big_capture<T, capacity> = true>
move_callback(T&& function)
{
static_assert(
not ForbidAlloc,
"Failed to store provided callback in std::move_callback specialization that forbids heap allocations.");
using FunT = typename std::decay<T>::type;
static const task_details::heap_table_t<FunT, R, Args...> heap_oper_table{};
oper_ptr = &heap_oper_table;
@ -172,7 +175,7 @@ public:
return *this;
}
R operator()(Args&&... args) const noexcept { return oper_ptr->call(&buffer, std::forward<Args>(args)...); }
R operator()(Args... args) const noexcept { return oper_ptr->call(&buffer, std::forward<Args>(args)...); }
bool is_empty() const { return oper_ptr == &empty_table; }
bool is_in_small_buffer() const { return oper_ptr->is_in_small_buffer(); }
@ -185,8 +188,8 @@ private:
const oper_table_t* oper_ptr;
};
template <typename R, typename... Args, size_t Capacity>
constexpr task_details::empty_table_t<R, Args...> move_callback<R(Args...), Capacity>::empty_table;
template <typename R, typename... Args, size_t Capacity, bool ForbidAlloc>
constexpr task_details::empty_table_t<R, Args...> move_callback<R(Args...), Capacity, ForbidAlloc>::empty_table;
//! Generic move task
using move_task_t = move_callback<void()>;

@ -0,0 +1,184 @@
/**
*
* \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_BATCH_MEM_POOL_H
#define SRSRAN_BATCH_MEM_POOL_H
#include "memblock_cache.h"
#include "pool_utils.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/thread_pool.h"
#include <memory>
#include <mutex>
namespace srsran {
/**
* Non-thread-safe, node-based memory pool that allocates nodes in batches of "objs_per_batch" > 1, and caches
* allocated blocks on deallocation
*/
class growing_batch_mem_pool
{
public:
explicit growing_batch_mem_pool(size_t objs_per_batch_,
size_t node_size_,
size_t node_alignment_,
int init_size = -1) :
objs_per_batch(objs_per_batch_),
memblock_size(std::max(node_size_, free_memblock_list::min_memblock_size())),
allocated(objs_per_batch * memblock_size, std::max(node_alignment_, free_memblock_list::min_memblock_align()))
{
size_t N = init_size < 0 ? objs_per_batch_ : init_size;
while (N > cache_size()) {
allocate_batch();
}
}
~growing_batch_mem_pool()
{
srsran_assert(cache_size() == size(), "Not all nodes have been deallocated yet (%zd < %zd)", cache_size(), size());
}
size_t get_node_max_size() const { return memblock_size; }
void clear()
{
free_list.clear();
allocated.clear();
}
size_t cache_size() const { return free_list.size(); }
size_t size() const { return allocated.size() * objs_per_batch; }
void allocate_batch()
{
uint8_t* batch_payload = static_cast<uint8_t*>(allocated.allocate_block());
for (size_t i = 0; i < objs_per_batch; ++i) {
void* cache_node = batch_payload + i * memblock_size;
free_list.push(cache_node);
}
}
void* allocate_node()
{
if (free_list.empty()) {
allocate_batch();
}
return free_list.pop();
}
void deallocate_node(void* ptr) { free_list.push(ptr); }
private:
const size_t objs_per_batch;
const size_t memblock_size;
memblock_stack allocated;
free_memblock_list free_list;
};
/**
* Thread-safe object pool specialized in allocating batches of objects in a preemptive way in a background thread
* to minimize latency.
* Note: The dispatched allocation jobs may outlive the pool. To handle this, the pool state is passed to jobs via a
* shared ptr.
*/
class background_mem_pool
{
public:
const size_t batch_threshold;
explicit background_mem_pool(size_t nodes_per_batch_, size_t node_size_, size_t thres_, int initial_size = -1) :
batch_threshold(thres_),
state(std::make_shared<detached_pool_state>(this)),
grow_pool(nodes_per_batch_, node_size_, detail::max_alignment, initial_size)
{
srsran_assert(batch_threshold > 1, "Invalid arguments for background memory pool");
}
~background_mem_pool()
{
std::lock_guard<std::mutex> lock(state->mutex);
state->pool = nullptr;
grow_pool.clear();
}
/// alloc new object space. If no memory is pre-reserved in the pool, malloc is called to allocate new batch.
void* allocate_node(size_t sz)
{
srsran_assert(sz <= grow_pool.get_node_max_size(),
"Mismatch of allocated node size=%zd and object size=%zd",
sz,
grow_pool.get_node_max_size());
std::lock_guard<std::mutex> lock(state->mutex);
void* node = grow_pool.allocate_node();
if (grow_pool.size() < batch_threshold) {
allocate_batch_in_background_unlocked();
}
return node;
}
void deallocate_node(void* p)
{
std::lock_guard<std::mutex> lock(state->mutex);
grow_pool.deallocate_node(p);
}
void allocate_batch()
{
std::lock_guard<std::mutex> lock(state->mutex);
grow_pool.allocate_batch();
}
size_t get_node_max_size() const { return grow_pool.get_node_max_size(); }
size_t cache_size() const
{
std::lock_guard<std::mutex> lock(state->mutex);
return grow_pool.cache_size();
}
private:
void allocate_batch_in_background_unlocked()
{
if (state->dispatched) {
// new batch allocation already ongoing
return;
}
state->dispatched = true;
std::shared_ptr<detached_pool_state> state_sptr = state;
get_background_workers().push_task([state_sptr]() {
std::lock_guard<std::mutex> lock(state_sptr->mutex);
// check if pool has not been destroyed
if (state_sptr->pool != nullptr) {
auto* pool = state_sptr->pool;
do {
pool->grow_pool.allocate_batch();
} while (pool->grow_pool.cache_size() < pool->batch_threshold);
}
state_sptr->dispatched = false;
});
}
// State is stored in a shared_ptr that may outlive the pool.
struct detached_pool_state {
std::mutex mutex;
background_mem_pool* pool;
bool dispatched = false;
explicit detached_pool_state(background_mem_pool* pool_) : pool(pool_) {}
};
std::shared_ptr<detached_pool_state> state;
growing_batch_mem_pool grow_pool;
};
} // namespace srsran
#endif // SRSRAN_BATCH_MEM_POOL_H

@ -0,0 +1,112 @@
/**
*
* \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_CIRCULAR_MAP_STACK_POOL_H
#define SRSRAN_CIRCULAR_MAP_STACK_POOL_H
#include "batch_mem_pool.h"
#include "linear_allocator.h"
#include "srsran/adt/circular_array.h"
#include <mutex>
namespace srsran {
template <size_t NofStacks>
class circular_stack_pool
{
struct mem_block_elem_t {
std::mutex mutex;
size_t key = std::numeric_limits<size_t>::max();
size_t count = 0;
linear_allocator alloc;
void clear()
{
key = std::numeric_limits<size_t>::max();
count = 0;
alloc.clear();
}
};
public:
circular_stack_pool(size_t nof_objs_per_batch, size_t stack_size, size_t batch_thres, int initial_size = -1) :
central_cache(std::min(NofStacks, nof_objs_per_batch), stack_size, batch_thres, initial_size),
logger(srslog::fetch_basic_logger("POOL"))
{}
circular_stack_pool(circular_stack_pool&&) = delete;
circular_stack_pool(const circular_stack_pool&) = delete;
circular_stack_pool& operator=(circular_stack_pool&&) = delete;
circular_stack_pool& operator=(const circular_stack_pool&) = delete;
~circular_stack_pool()
{
for (mem_block_elem_t& elem : pools) {
std::unique_lock<std::mutex> lock(elem.mutex);
srsran_assert(elem.count == 0, "There are missing deallocations for stack id=%zd", elem.key);
if (elem.alloc.is_init()) {
void* ptr = elem.alloc.memblock_ptr();
elem.alloc.clear();
central_cache.deallocate_node(ptr);
}
}
}
void* allocate(size_t key, size_t size, size_t alignment) noexcept
{
size_t idx = key % NofStacks;
mem_block_elem_t& elem = pools[idx];
std::unique_lock<std::mutex> lock(elem.mutex);
if (not elem.alloc.is_init()) {
void* block = central_cache.allocate_node(central_cache.get_node_max_size());
if (block == nullptr) {
logger.warning("Failed to allocate memory block from central cache");
return nullptr;
}
elem.key = key;
elem.alloc = linear_allocator(block, central_cache.get_node_max_size());
}
void* ptr = elem.alloc.allocate(size, alignment);
if (ptr == nullptr) {
logger.warning("No space left in memory block with key=%zd of circular stack pool", key);
} else {
elem.count++;
}
return ptr;
}
void deallocate(size_t key, void* p)
{
size_t idx = key % NofStacks;
mem_block_elem_t& elem = pools[idx];
std::lock_guard<std::mutex> lock(elem.mutex);
elem.alloc.deallocate(p);
elem.count--;
if (elem.count == 0) {
// return back to central cache
void* ptr = elem.alloc.memblock_ptr();
elem.clear();
central_cache.deallocate_node(ptr);
}
}
void allocate_batch() { central_cache.allocate_batch(); }
size_t cache_size() const { return central_cache.cache_size(); }
private:
srsran::circular_array<mem_block_elem_t, NofStacks> pools;
srsran::background_mem_pool central_cache;
srslog::basic_logger& logger;
};
} // namespace srsran
#endif // SRSRAN_CIRCULAR_MAP_STACK_POOL_H

@ -168,12 +168,12 @@ public:
private:
struct worker_ctxt {
std::thread::id id;
memblock_cache cache;
free_memblock_list cache;
worker_ctxt() : id(std::this_thread::get_id()) {}
~worker_ctxt()
{
mutexed_memblock_cache& central_cache = pool_type::get_instance()->central_mem_cache;
concurrent_free_memblock_list& central_cache = pool_type::get_instance()->central_mem_cache;
central_cache.steal_blocks(cache, cache.size());
}
};
@ -198,7 +198,7 @@ private:
size_t local_growth_thres = 0;
srslog::basic_logger* logger = nullptr;
mutexed_memblock_cache central_mem_cache;
concurrent_free_memblock_list central_mem_cache;
std::mutex mutex;
std::vector<std::unique_ptr<obj_storage_t> > allocated_blocks;
};

@ -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_LINEAR_ALLOCATOR_H
#define SRSRAN_LINEAR_ALLOCATOR_H
#include "pool_utils.h"
#include "srsran/common/srsran_assert.h"
namespace srsran {
class linear_allocator
{
public:
linear_allocator() = default;
linear_allocator(void* start_, void* end_) :
start(static_cast<uint8_t*>(start_)), end(static_cast<uint8_t*>(end_)), cur(start)
{}
linear_allocator(void* start_, size_t sz) : start(static_cast<uint8_t*>(start_)), end(start + sz), cur(start) {}
linear_allocator(const linear_allocator& other) = delete;
linear_allocator(linear_allocator&& other) noexcept : start(other.start), end(other.end), cur(other.cur)
{
other.clear();
}
linear_allocator& operator=(const linear_allocator& other) = delete;
linear_allocator& operator =(linear_allocator&& other) noexcept
{
start = other.start;
end = other.end;
cur = other.cur;
other.clear();
return *this;
}
void* allocate(size_t sz, size_t alignment)
{
void* alloc_start = align_to(cur, alignment);
uint8_t* new_cur = static_cast<uint8_t*>(alloc_start) + sz;
if (new_cur > end) {
// Cannot fit allocation in memory block
return nullptr;
}
cur = new_cur;
return alloc_start;
}
void deallocate(void* p) { srsran_assert(p >= start and p < end, "pointer does not belong to pool"); }
size_t nof_bytes_allocated() const { return cur - start; }
size_t nof_bytes_left() const { return end - cur; }
size_t size() const { return end - start; }
bool is_init() const { return start != end; }
void* memblock_ptr() { return static_cast<void*>(start); }
void clear()
{
start = nullptr;
cur = nullptr;
end = nullptr;
}
protected:
uint8_t* start = nullptr;
uint8_t* end = nullptr;
uint8_t* cur = nullptr;
};
} // namespace srsran
#endif // SRSRAN_LINEAR_ALLOCATOR_H

@ -44,7 +44,7 @@ template <typename T, bool ThreadSafe = false>
class big_obj_pool
{
// memory stack type derivation (thread safe or not)
using stack_type = typename std::conditional<ThreadSafe, mutexed_memblock_cache, memblock_cache>::type;
using stack_type = typename std::conditional<ThreadSafe, concurrent_free_memblock_list, free_memblock_list>::type;
// memory stack to cache allocate memory chunks
stack_type stack;
@ -56,8 +56,8 @@ public:
void* allocate_node(size_t sz)
{
assert(sz == sizeof(T));
static const size_t blocksize = std::max(sizeof(T), memblock_cache::min_memblock_size());
uint8_t* block = stack.try_pop();
static const size_t blocksize = std::max(sizeof(T), free_memblock_list::min_memblock_size());
void* block = stack.try_pop();
if (block == nullptr) {
block = new uint8_t[blocksize];
}
@ -67,16 +67,16 @@ public:
void deallocate_node(void* p)
{
if (p != nullptr) {
stack.push(static_cast<uint8_t*>(p));
stack.push(p);
}
}
/// Pre-reserve N memory chunks for future object allocations
void reserve(size_t N)
{
static const size_t blocksize = std::max(sizeof(T), memblock_cache::min_memblock_size());
static const size_t blocksize = std::max(sizeof(T), free_memblock_list::min_memblock_size());
for (size_t i = 0; i < N; ++i) {
stack.push(new uint8_t[blocksize]);
stack.push(static_cast<void*>(new uint8_t[blocksize]));
}
}
@ -84,10 +84,10 @@ public:
void clear()
{
uint8_t* block = stack.try_pop();
uint8_t* block = static_cast<uint8_t*>(stack.try_pop());
while (block != nullptr) {
delete[] block;
block = stack.try_pop();
block = static_cast<uint8_t*>(stack.try_pop());
}
}
};
@ -128,7 +128,7 @@ public:
{
assert(sz == sizeof(T));
std::lock_guard<std::mutex> lock(mutex);
uint8_t* block = obj_cache.try_pop();
void* block = obj_cache.try_pop();
if (block != nullptr) {
// allocation successful
@ -179,7 +179,7 @@ private:
// memory stack to cache allocate memory chunks
std::mutex mutex;
memblock_cache obj_cache;
free_memblock_list obj_cache;
std::vector<std::unique_ptr<batch_obj_t> > batches;
};

@ -22,90 +22,196 @@
#ifndef SRSRAN_MEMBLOCK_CACHE_H
#define SRSRAN_MEMBLOCK_CACHE_H
#include "pool_utils.h"
#include <mutex>
namespace srsran {
/// Stores provided mem blocks in a stack in an non-owning manner. Not thread-safe
class memblock_cache
namespace detail {
class intrusive_memblock_list
{
public:
struct node {
node* prev;
explicit node(node* prev_) : prev(prev_) {}
node* next;
explicit node(node* prev_) : next(prev_) {}
};
node* head = nullptr;
size_t count = 0;
public:
constexpr static size_t min_memblock_size() { return sizeof(node); }
constexpr static size_t min_memblock_align() { return alignof(node); }
memblock_cache() = default;
void push(void* block) noexcept
{
srsran_assert(is_aligned(block, min_memblock_align()), "The provided memory block is not aligned");
node* ptr = ::new (block) node(head);
head = ptr;
count++;
}
memblock_cache(const memblock_cache&) = delete;
void* pop() noexcept
{
srsran_assert(not empty(), "pop() called on empty list");
node* last_head = head;
head = head->next;
last_head->~node();
count--;
return static_cast<void*>(last_head);
}
memblock_cache(memblock_cache&& other) noexcept : head(other.head) { other.head = nullptr; }
void* try_pop() noexcept { return empty() ? nullptr : pop(); }
memblock_cache& operator=(const memblock_cache&) = delete;
bool empty() const noexcept { return head == nullptr; }
size_t size() const { return count; }
memblock_cache& operator=(memblock_cache&& other) noexcept
void clear() noexcept
{
head = other.head;
other.head = nullptr;
return *this;
head = nullptr;
count = 0;
}
};
void push(void* block) noexcept
} // namespace detail
/**
* List of memory blocks. It overwrites bytes of blocks passed via push(void*). Thus, it is not safe to use in any
* pool of initialized objects
*/
class free_memblock_list : public detail::intrusive_memblock_list
{
private:
using base_t = detail::intrusive_memblock_list;
using base_t::count;
using base_t::head;
};
/**
* List of memory blocks, each memory block containing a node. Memory Structure:
* memory block 1 memory block
* [ next | node ] [ next | node ]
* '--------------^ '-----------> nullptr
*/
class memblock_node_list : public detail::intrusive_memblock_list
{
using base_t = detail::intrusive_memblock_list;
using base_t::count;
using base_t::head;
using base_t::try_pop;
public:
const size_t memblock_alignment;
const size_t header_size;
const size_t payload_size;
const size_t memblock_size;
explicit memblock_node_list(size_t node_size_, size_t node_alignment_ = detail::max_alignment) :
memblock_alignment(std::max(free_memblock_list::min_memblock_align(), node_alignment_)),
header_size(align_next(base_t::min_memblock_size(), memblock_alignment)),
payload_size(align_next(node_size_, memblock_alignment)),
memblock_size(header_size + payload_size)
{
srsran_assert(node_size_ > 0 and is_valid_alignment(node_alignment_),
"Invalid arguments node size=%zd,alignment=%zd",
node_size_,
node_alignment_);
}
void* get_node_header(void* payload_addr)
{
srsran_assert(is_aligned(payload_addr, memblock_alignment), "Provided address is not valid");
return static_cast<void*>(static_cast<uint8_t*>(payload_addr) - header_size);
}
/// returns address of memblock payload (skips memblock header)
void* top() noexcept { return static_cast<void*>(reinterpret_cast<uint8_t*>(this->head) + header_size); }
void steal_top(intrusive_memblock_list& other) noexcept
{
// printf("head: %ld\n", (long)head);
node* next = ::new (block) node(head);
head = next;
srsran_assert(not other.empty(), "Trying to steal from empty memblock list");
node* other_head = other.head;
other.head = other.head->next;
other_head->next = head;
head = other_head;
other.count--;
count++;
}
};
uint8_t* try_pop() noexcept
/// Similar to node_memblock_list, but manages the allocation/deallocation of memory blocks
class memblock_stack
{
public:
explicit memblock_stack(size_t node_size_, size_t node_alignment_ = detail::max_alignment) :
node_list(node_size_, node_alignment_)
{}
memblock_stack(const memblock_stack&) = delete;
memblock_stack(memblock_stack&& other) noexcept = delete;
memblock_stack& operator=(const memblock_stack&) = delete;
memblock_stack& operator=(memblock_stack&&) = delete;
~memblock_stack() { clear(); }
void clear()
{
if (is_empty()) {
return nullptr;
while (not empty()) {
deallocate_block();
}
node* last_head = head;
head = head->prev;
count--;
return (uint8_t*)last_head;
}
bool is_empty() const { return head == nullptr; }
size_t get_memblock_size() const { return node_list.memblock_size; }
size_t get_node_max_size() const { return node_list.payload_size; }
size_t size() const { return count; }
void* allocate_block()
{
node_list.push(new uint8_t[node_list.memblock_size]);
return current_node();
}
void clear() { head = nullptr; }
void deallocate_block() noexcept
{
uint8_t* block = static_cast<uint8_t*>(node_list.pop());
delete[] block;
}
bool empty() const noexcept { return node_list.empty(); }
size_t size() const noexcept { return node_list.size(); }
void* current_node() noexcept { return node_list.top(); }
void steal_top(memblock_stack& other) noexcept { return node_list.steal_top(other.node_list); }
private:
node* head = nullptr;
size_t count = 0;
static size_t get_memblock_start_offset(size_t node_alignment)
{
return align_next(detail::intrusive_memblock_list::min_memblock_size(), node_alignment);
}
static size_t get_memblock_size(size_t node_size, size_t node_alignment)
{
return align_next(get_memblock_start_offset(node_alignment) + node_size, detail::max_alignment);
}
memblock_node_list node_list;
};
/// memblock stack that mutexes pushing/popping
class mutexed_memblock_cache
class concurrent_free_memblock_list
{
public:
mutexed_memblock_cache() = default;
mutexed_memblock_cache(const mutexed_memblock_cache&) = delete;
mutexed_memblock_cache(mutexed_memblock_cache&& other) noexcept
concurrent_free_memblock_list() = default;
concurrent_free_memblock_list(const concurrent_free_memblock_list&) = delete;
concurrent_free_memblock_list(concurrent_free_memblock_list&& other) noexcept
{
std::unique_lock<std::mutex> lk1(other.mutex, std::defer_lock);
std::unique_lock<std::mutex> lk2(mutex, std::defer_lock);
std::lock(lk1, lk2);
stack = std::move(other.stack);
stack = other.stack;
}
mutexed_memblock_cache& operator=(const mutexed_memblock_cache&) = delete;
mutexed_memblock_cache& operator=(mutexed_memblock_cache&& other) noexcept
concurrent_free_memblock_list& operator=(const concurrent_free_memblock_list&) = delete;
concurrent_free_memblock_list& operator=(concurrent_free_memblock_list&& other) noexcept
{
std::unique_lock<std::mutex> lk1(other.mutex, std::defer_lock);
std::unique_lock<std::mutex> lk2(mutex, std::defer_lock);
std::lock(lk1, lk2);
stack = std::move(other.stack);
stack = other.stack;
return *this;
}
@ -115,18 +221,18 @@ public:
stack.push(block);
}
void steal_blocks(memblock_cache& other, size_t max_n) noexcept
void steal_blocks(free_memblock_list& other, size_t max_n) noexcept
{
std::lock_guard<std::mutex> lock(mutex);
for (size_t i = 0; i < max_n and not other.is_empty(); ++i) {
for (size_t i = 0; i < max_n and not other.empty(); ++i) {
stack.push(other.try_pop());
}
}
uint8_t* try_pop() noexcept
void* try_pop() noexcept
{
std::lock_guard<std::mutex> lock(mutex);
uint8_t* block = stack.try_pop();
void* block = stack.try_pop();
return block;
}
@ -144,7 +250,7 @@ public:
return i;
}
bool is_empty() const noexcept { return stack.is_empty(); }
bool empty() const noexcept { return stack.empty(); }
size_t size() const noexcept
{
@ -159,10 +265,39 @@ public:
}
private:
memblock_cache stack;
free_memblock_list stack;
mutable std::mutex mutex;
};
/**
* Manages the allocation, caching and deallocation of memory blocks.
* On alloc, a memory block is stolen from cache. If cache is empty, malloc/new is called.
* Only the last allocated memory block can be deallocated.
*/
class cached_memblock_stack
{
public:
explicit cached_memblock_stack(size_t block_size_) : used(block_size_), cache(block_size_) {}
void* allocate_block()
{
if (cache.empty()) {
used.allocate_block();
} else {
used.steal_top(cache);
}
return used.current_node();
}
void* current_node() noexcept { return used.current_node(); }
void deallocate_block() noexcept { cache.steal_top(used); }
size_t cache_size() const noexcept { return cache.size(); }
private:
memblock_stack used;
memblock_stack cache;
};
} // namespace srsran
#endif // SRSRAN_MEMBLOCK_CACHE_H

@ -0,0 +1,219 @@
/**
*
* \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_OBJ_POOL_H
#define SRSRAN_OBJ_POOL_H
#include "batch_mem_pool.h"
#include "memblock_cache.h"
#include "pool_interface.h"
namespace srsran {
template <typename T>
class background_obj_pool;
template <typename T>
class growing_batch_obj_pool final : public obj_pool_itf<T>
{
static size_t memblock_size()
{
/// Node Structure [ node header | (pad to node alignment) | node size | (pad to node header alignment) ]
return align_next(align_next(free_memblock_list::min_memblock_size(), alignof(T)) + sizeof(T),
free_memblock_list::min_memblock_align());
}
static size_t batch_size(size_t nof_objs_per_batch)
{
/// Batch Structure: [allocated stack header | (pad max alignment) | [memblock] x objs_per_batch ]
return align_next(detail::max_alignment + (memblock_size() * nof_objs_per_batch), detail::max_alignment);
}
public:
using init_mem_oper_t = srsran::move_callback<void(void*)>;
using recycle_oper_t = srsran::move_callback<void(T&)>;
explicit growing_batch_obj_pool(size_t objs_per_batch_,
int init_size = -1,
init_mem_oper_t init_oper_ = detail::inplace_default_ctor_operator<T>{},
recycle_oper_t recycle_oper_ = detail::noop_operator{}) :
objs_per_batch(objs_per_batch_),
init_oper(std::move(init_oper_)),
recycle_oper(std::move(recycle_oper_)),
allocated(batch_size(objs_per_batch_), detail::max_alignment),
cache(sizeof(T), alignof(T))
{
size_t N = init_size < 0 ? objs_per_batch_ : init_size;
while (N > cache.size()) {
allocate_batch();
}
}
~growing_batch_obj_pool() { clear(); }
void clear()
{
if (not allocated.empty()) {
srsran_assert(allocated.size() * objs_per_batch == cache_size(),
"Not all objects have been deallocated (%zd < %zd)",
cache_size(),
allocated.size() * objs_per_batch);
while (not cache.empty()) {
void* node_payload = cache.top();
static_cast<T*>(node_payload)->~T();
cache.pop();
}
allocated.clear();
}
}
unique_pool_ptr<T> make() final
{
return unique_pool_ptr<T>(do_allocate(), [this](T* ptr) {
// dtor is not called, as object is going to be recycled
do_deallocate(ptr);
});
}
void allocate_batch()
{
uint8_t* batch_payload = static_cast<uint8_t*>(allocated.allocate_block());
for (size_t i = 0; i < objs_per_batch; ++i) {
void* cache_node = batch_payload + (i * cache.memblock_size);
cache.push(cache_node);
init_oper(cache.top());
}
}
size_t cache_size() const { return cache.size(); }
private:
friend class background_obj_pool<T>;
T* do_allocate()
{
if (cache.empty()) {
allocate_batch();
}
void* top = cache.top();
cache.pop();
return static_cast<T*>(top);
}
void do_deallocate(T* payload_ptr)
{
recycle_oper(*payload_ptr);
void* header_ptr = cache.get_node_header(static_cast<void*>(payload_ptr));
cache.push(header_ptr);
}
// args
const size_t objs_per_batch;
init_mem_oper_t init_oper;
recycle_oper_t recycle_oper;
memblock_stack allocated;
memblock_node_list cache;
};
/**
* Thread-safe object pool specialized in allocating batches of objects in a preemptive way in a background thread
* to minimize latency.
* Note: The dispatched allocation jobs may outlive the pool. To handle this, the pool state is passed to jobs via a
* shared ptr.
*/
template <typename T>
class background_obj_pool final : public obj_pool_itf<T>
{
public:
using init_mem_oper_t = typename growing_batch_obj_pool<T>::init_mem_oper_t;
using recycle_oper_t = typename growing_batch_obj_pool<T>::recycle_oper_t;
explicit background_obj_pool(size_t nof_objs_per_batch,
size_t thres_,
int init_size = -1,
init_mem_oper_t init_oper_ = detail::inplace_default_ctor_operator<T>{},
recycle_oper_t recycle_oper_ = detail::noop_operator{}) :
thres(thres_),
state(std::make_shared<detached_pool_state>(this)),
grow_pool(nof_objs_per_batch, init_size, std::move(init_oper_), std::move(recycle_oper_))
{
srsran_assert(thres_ > 1, "The provided threshold=%zd is not valid", thres_);
}
~background_obj_pool()
{
std::lock_guard<std::mutex> lock(state->mutex);
state->pool = nullptr;
grow_pool.clear();
}
unique_pool_ptr<T> make() final
{
return unique_pool_ptr<T>(do_allocate(), [this](T* ptr) {
// dtor is not called, as object is going to be recycled
do_deallocate(ptr);
});
}
size_t cache_size() const { return grow_pool.cache_size(); }
private:
T* do_allocate()
{
std::lock_guard<std::mutex> lock(state->mutex);
T* obj = grow_pool.do_allocate();
if (grow_pool.cache_size() < thres) {
allocate_batch_in_background_();
}
return obj;
}
void do_deallocate(T* ptr)
{
std::lock_guard<std::mutex> lock(state->mutex);
return grow_pool.do_deallocate(ptr);
}
void allocate_batch_in_background_()
{
if (state->dispatched) {
// new batch allocation already ongoing
return;
}
state->dispatched = true;
std::shared_ptr<detached_pool_state> state_sptr = state;
get_background_workers().push_task([state_sptr]() {
std::lock_guard<std::mutex> lock(state_sptr->mutex);
if (state_sptr->pool != nullptr) {
auto* pool = state_sptr->pool;
do {
pool->grow_pool.allocate_batch();
} while (pool->grow_pool.cache_size() < pool->thres);
}
state_sptr->dispatched = false;
});
}
size_t thres;
// state of pool is detached because pool may be destroyed while batches are being allocated in the background
struct detached_pool_state {
std::mutex mutex;
background_obj_pool<T>* pool;
bool dispatched = false;
explicit detached_pool_state(background_obj_pool<T>* pool_) : pool(pool_) {}
};
std::shared_ptr<detached_pool_state> state;
growing_batch_obj_pool<T> grow_pool;
};
} // namespace srsran
#endif // SRSRAN_OBJ_POOL_H

@ -0,0 +1,62 @@
/**
*
* \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_POOL_INTERFACE_H
#define SRSRAN_POOL_INTERFACE_H
#include "srsran/adt/move_callback.h"
namespace srsran {
/// unique ptr with type-erased dtor, so that it can be used by any object or memory pool
constexpr size_t unique_pool_deleter_small_buffer = sizeof(void*) * 2u;
template <typename T>
using unique_pool_ptr = std::unique_ptr<T, srsran::move_callback<void(T*), unique_pool_deleter_small_buffer> >;
/// Common object pool interface
template <typename T>
class obj_pool_itf
{
public:
using object_type = T;
obj_pool_itf() = default;
// Object pool address should not change
obj_pool_itf(const obj_pool_itf&) = delete;
obj_pool_itf(obj_pool_itf&&) = delete;
obj_pool_itf& operator=(const obj_pool_itf&) = delete;
obj_pool_itf& operator=(obj_pool_itf&&) = delete;
virtual ~obj_pool_itf() = default;
virtual unique_pool_ptr<T> make() = 0;
};
/// Allocate object in memory pool
template <typename T, typename MemPool, typename... Args>
unique_pool_ptr<T> make_pool_obj_with_heap_fallback(MemPool& mempool, Args&&... args)
{
void* block = mempool.allocate(sizeof(T), alignof(T));
if (block == nullptr) {
return unique_pool_ptr<T>(new T(std::forward<Args>(args)...), std::default_delete<T>());
}
new (block) T(std::forward<Args>(args)...);
return unique_pool_ptr<T>(block, [&mempool](T* ptr) {
if (ptr != nullptr) {
ptr->~T();
mempool.deallocate(ptr);
}
});
}
} // namespace srsran
#endif // SRSRAN_POOL_INTERFACE_H

@ -0,0 +1,64 @@
/**
*
* \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_POOL_UTILS_H
#define SRSRAN_POOL_UTILS_H
#include "../move_callback.h"
#include <memory>
namespace srsran {
namespace detail {
template <typename T>
struct inplace_default_ctor_operator {
void operator()(void* ptr) { new (ptr) T(); }
};
struct noop_operator {
template <typename T>
void operator()(T&& t) const
{
// do nothing
}
};
} // namespace detail
/// check if alignment is power of 2
constexpr bool is_valid_alignment(std::size_t alignment)
{
return alignment && (alignment & (alignment - 1)) == 0u;
}
inline bool is_aligned(void* ptr, std::size_t alignment)
{
return (reinterpret_cast<std::uintptr_t>(ptr) & (alignment - 1)) == 0;
}
constexpr std::uintptr_t align_next(std::uintptr_t pos, size_t alignment)
{
return (pos + (alignment - 1)) & ~(alignment - 1);
}
inline void* align_to(void* pos, size_t alignment)
{
return reinterpret_cast<void*>(align_next(reinterpret_cast<std::uintptr_t>(pos), alignment));
}
inline void* offset_byte_ptr(void* pos, size_t offset)
{
return static_cast<void*>(static_cast<uint8_t*>(pos) + offset);
}
} // namespace srsran
#endif // SRSRAN_POOL_UTILS_H

@ -45,7 +45,7 @@ private:
void write_mac_lte_pdu_to_net(srsran::mac_pcap_base::pcap_pdu_t& pdu);
void write_mac_nr_pdu_to_net(srsran::mac_pcap_base::pcap_pdu_t& pdu);
srsran::socket_handler_t socket;
srsran::unique_socket socket;
struct sockaddr_in client_addr;
};
} // namespace srsran

@ -23,20 +23,18 @@
#define SRSRAN_RX_SOCKET_HANDLER_H
#include "srsran/common/buffer_pool.h"
#include "srsran/common/multiqueue.h"
#include "srsran/common/threads.h"
#include <arpa/inet.h>
#include <functional>
#include <map>
#include <mutex>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <queue>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // for the pipe
namespace srsran {
@ -67,20 +65,19 @@ bool connect_to(int fd, const char* dest_addr_str, int dest_port, sockaddr_in* d
/**
* Description: Net socket class with convenience methods for connecting, binding, and opening socket
*/
class socket_handler_t
class unique_socket
{
public:
socket_handler_t() = default;
socket_handler_t(const socket_handler_t&) = delete;
socket_handler_t(socket_handler_t&& other) noexcept;
~socket_handler_t();
socket_handler_t& operator=(const socket_handler_t&) = delete;
socket_handler_t& operator =(socket_handler_t&&) noexcept;
unique_socket() = default;
unique_socket(const unique_socket&) = delete;
unique_socket(unique_socket&& other) noexcept;
~unique_socket();
unique_socket& operator=(const unique_socket&) = delete;
unique_socket& operator =(unique_socket&&) noexcept;
void close();
void reset();
bool is_init() const { return sockfd >= 0; }
bool is_open() const { return sockfd >= 0; }
int fd() const { return sockfd; }
const sockaddr_in& get_addr_in() const { return addr; }
std::string get_ip() const { return net_utils::get_ip(addr); }
@ -89,7 +86,7 @@ public:
bool bind_addr(const char* bind_addr_str, int port);
bool connect_to(const char* dest_addr_str, int dest_port, sockaddr_in* dest_sockaddr = nullptr);
bool open_socket(net_utils::addr_family ip, net_utils::socket_type socket_type, net_utils::protocol_type protocol);
int get_socket() { return sockfd; };
int get_socket() const { return sockfd; };
protected:
sockaddr_in addr = {};
@ -98,14 +95,8 @@ protected:
namespace net_utils {
bool sctp_init_client(socket_handler_t* socket, net_utils::socket_type socktype, const char* bind_addr_str);
bool sctp_init_server(socket_handler_t* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port);
// TODO: for TCP and UDP
bool tcp_make_server(socket_handler_t* socket, const char* bind_addr_str, int port, int nof_connections = 1);
int tcp_accept(socket_handler_t* socket, sockaddr_in* destaddr);
int tcp_read(int remotefd, void* buf, size_t nbytes);
int tcp_send(int remotefd, const void* buf, size_t nbytes);
bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str);
bool sctp_init_server(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port);
} // namespace net_utils
@ -113,63 +104,97 @@ int tcp_send(int remotefd, const void* buf, size_t nbytes);
* Rx multisocket handler
***************************/
class socket_manager_itf
{
public:
/// Callback called when socket fd (passed as argument) has data
using recv_callback_t = srsran::move_callback<bool(int)>;
explicit socket_manager_itf(srslog::basic_logger& logger_) : logger(logger_) {}
socket_manager_itf(socket_manager_itf&&) = delete;
socket_manager_itf(const socket_manager_itf&) = delete;
socket_manager_itf& operator=(const socket_manager_itf&) = delete;
socket_manager_itf& operator=(socket_manager_itf&&) = delete;
virtual ~socket_manager_itf() = default;
/// Register (fd, callback). callback is called within socket thread when fd has data.
virtual bool add_socket_handler(int fd, recv_callback_t handler) = 0;
/// remove registered socket fd
virtual bool remove_socket(int fd) = 0;
protected:
srslog::basic_logger& logger;
};
/**
* Description - Instantiates a thread that will block waiting for IO from multiple sockets, via a select
* The user can register their own (socket fd, data handler) in this class via the
* add_socket_handler(fd, task) API or its other variants
*/
class rx_multisocket_handler final : public thread
class socket_manager final : public thread, public socket_manager_itf
{
using recv_callback_t = socket_manager_itf::recv_callback_t;
public:
// polymorphic callback to handle the socket recv
class recv_task
{
public:
virtual ~recv_task() = default;
virtual bool operator()(int fd) = 0; // returns false, if socket needs to be removed
};
using task_callback_t = std::unique_ptr<recv_task>;
using recvfrom_callback_t = std::function<void(srsran::unique_byte_buffer_t, const sockaddr_in&)>;
using sctp_recv_callback_t =
std::function<void(srsran::unique_byte_buffer_t, const sockaddr_in&, const sctp_sndrcvinfo&, int)>;
rx_multisocket_handler(std::string name_, srslog::basic_logger& logger, int thread_prio = 65);
rx_multisocket_handler(rx_multisocket_handler&&) = delete;
rx_multisocket_handler(const rx_multisocket_handler&) = delete;
rx_multisocket_handler& operator=(const rx_multisocket_handler&) = delete;
rx_multisocket_handler& operator=(rx_multisocket_handler&&) = delete;
~rx_multisocket_handler();
socket_manager();
~socket_manager() final;
void stop();
bool remove_socket(int fd);
bool add_socket_handler(int fd, task_callback_t handler);
// convenience methods for recv using buffer pool
bool add_socket_pdu_handler(int fd, recvfrom_callback_t pdu_task);
bool add_socket_sctp_pdu_handler(int fd, sctp_recv_callback_t task);
bool remove_socket_nonblocking(int fd, bool signal_completion = false);
bool remove_socket(int fd) final;
bool add_socket_handler(int fd, recv_callback_t handler) final;
void run_thread() override;
private:
const int thread_prio = 65;
// used to unlock select
struct ctrl_cmd_t {
enum class cmd_id_t { EXIT, NEW_FD, RM_FD };
cmd_id_t cmd = cmd_id_t::EXIT;
int new_fd = -1;
bool signal_rm_complete = false;
};
std::map<int, rx_multisocket_handler::task_callback_t>::iterator
remove_socket_unprotected(int fd, fd_set* total_fd_set, int* max_fd);
// args
std::string name;
srslog::basic_logger& logger;
std::map<int, recv_callback_t>::iterator remove_socket_unprotected(int fd, fd_set* total_fd_set, int* max_fd);
// state
std::mutex socket_mutex;
std::map<int, task_callback_t> active_sockets;
std::map<int, recv_callback_t> active_sockets;
bool running = false;
int pipefd[2] = {};
int pipefd[2] = {-1, -1};
std::vector<int> rem_fd_tmp_list;
std::condition_variable rem_cvar;
};
/// Function signature for SDU byte buffers received from SCTP socket
using sctp_recv_callback_t =
srsran::move_callback<void(srsran::unique_byte_buffer_t, const sockaddr_in&, const sctp_sndrcvinfo&, int)>;
/// Function signature for SDU byte buffers received from any sockaddr_in-based socket
using recvfrom_callback_t = srsran::move_callback<void(srsran::unique_byte_buffer_t, const sockaddr_in&)>;
/**
* Helper function that creates a callback that is called when a SCTP socket has data, and does the following tasks:
* 1. receive SDU byte buffer from SCTP socket and associated metadata - sockaddr_in, sctp_sndrcvinfo, flags
* 2. dispatches the received SDU+metadata+rx_callback into the "queue"
* 3. potentially on a separate thread, the SDU+metadata+callback are popped from the queue, and callback is called with
* the SDU+metadata as arguments
* @param logger logger used by recv_callback_t to log any failure/reception of an SDU
* @param queue queue to which the SDU+metadata+callback are going to be dispatched
* @param rx_callback callback that is run when a new SDU arrives, from the thread that calls queue.pop()
* @return callback void(int) that can be registered in socket_manager
*/
socket_manager_itf::recv_callback_t
make_sctp_sdu_handler(srslog::basic_logger& logger, srsran::task_queue_handle& queue, sctp_recv_callback_t rx_callback);
/**
* Similar to make_sctp_sdu_handler, but for any sockaddr_in-based socket type
*/
socket_manager_itf::recv_callback_t
make_sdu_handler(srslog::basic_logger& logger, srsran::task_queue_handle& queue, recvfrom_callback_t rx_callback);
} // namespace srsran
#endif // SRSRAN_RX_SOCKET_HANDLER_H

@ -133,6 +133,7 @@ public:
sched->defer_callback(duration_ms, std::forward<F>(func));
}
void defer_task(srsran::move_task_t func) { sched->defer_task(std::move(func)); }
srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(); }
private:
task_scheduler* sched;

@ -67,6 +67,7 @@ public:
void run_thread();
void wait_to_start();
void finished();
bool is_stopped() const;
};
thread_pool(uint32_t nof_workers);
@ -97,7 +98,7 @@ private:
class task_thread_pool
{
using task_t = srsran::move_callback<void()>;
using task_t = srsran::move_callback<void(), default_move_callback_buffer_size, true>;
public:
task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255);

@ -29,19 +29,6 @@
namespace srsenb {
class stack_interface_phy_lte;
class stack_interface_s1ap_lte
{
public:
virtual void add_mme_socket(int fd) = 0;
virtual void remove_mme_socket(int fd) = 0;
};
class stack_interface_gtpu_lte
{
public:
virtual void add_gtpu_s1u_socket_handler(int fd) = 0;
virtual void add_gtpu_m1u_socket_handler(int fd) = 0;
};
} // namespace srsenb

@ -62,7 +62,7 @@ public:
/**
* List of DL scheduling results, one entry per cell/carrier
*/
typedef std::vector<dl_sched_t> dl_sched_list_t;
using dl_sched_list_t = srsran::bounded_vector<dl_sched_t, SRSRAN_MAX_CARRIERS>;
typedef struct {
uint16_t rnti;
@ -94,7 +94,7 @@ public:
/**
* List of UL scheduling results, one entry per cell/carrier
*/
typedef std::vector<ul_sched_t> ul_sched_list_t;
using ul_sched_list_t = srsran::bounded_vector<ul_sched_t, SRSRAN_MAX_CARRIERS>;
virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0;
virtual void rach_detected(uint32_t tti, uint32_t primary_cc_idx, uint32_t preamble_idx, uint32_t time_adv) = 0;

@ -24,10 +24,10 @@
#include <stdint.h>
#include "srsenb/hdr/common/common_enb.h"
#include "srsenb/hdr/phy/phy_metrics.h"
#include "srsenb/hdr/stack/mac/mac_metrics.h"
#include "srsenb/hdr/stack/rrc/rrc_metrics.h"
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srsenb/hdr/stack/upper/s1ap_metrics.h"
#include "srsran/common/metrics_hub.h"
#include "srsran/radio/radio_metrics.h"

@ -155,6 +155,27 @@ inline std::string to_string(const establishment_cause_t& cause)
return enum_to_text(options, (uint32_t)establishment_cause_t::nulltype, (uint32_t)cause);
}
enum class scg_failure_cause_t {
t310_expiry,
random_access_problem,
rlc_max_num_retx,
synch_recfg_fail_scg,
scg_recfg_fail,
srb3_integrity_fail,
nulltype
};
inline std::string to_string(const scg_failure_cause_t& cause)
{
constexpr static const char* options[] = {"t310_expiry",
"random_access_problem",
"rlc_max_num_retx",
"synch_recfg_fail_scg",
"scg_recfg_fail",
"srb3_integrity_fail",
"nulltype"};
return enum_to_text(options, (uint32_t)scg_failure_cause_t::nulltype, (uint32_t)cause);
}
/***************************
* PHY Config
**************************/

@ -38,7 +38,7 @@ struct phy_cfg_nr_t {
srsran_sch_hl_cfg_nr_t pusch = {};
srsran_pucch_nr_hl_cfg_t pucch = {};
srsran_prach_cfg_t prach = {};
srsran_ue_dl_nr_pdcch_cfg_t pdcch = {};
srsran_pdcch_cfg_nr_t pdcch = {};
srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {};
srsran_csi_hl_cfg_t csi = {};
@ -61,7 +61,7 @@ struct phy_cfg_nr_t {
// physicalCellGroupConfig
// pdsch-HARQ-ACK-Codebook: dynamic (1)
harq_ack.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
harq_ack.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// commonControlResourceSet
// controlResourceSetId: 1
@ -79,39 +79,6 @@ struct phy_cfg_nr_t {
}
pdcch.coreset_present[1] = true;
// SearchSpace
// searchSpaceId: 1
// controlResourceSetId: 1
// monitoringSlotPeriodicityAndOffset: sl1 (0)
// sl1: NULL
// monitoringSymbolsWithinSlot: 8000 [bit length 14, 2 LSB pad bits, 1000 0000 0000 00.. decimal value 8192]
// nrofCandidates
// aggregationLevel1: n0 (0)
// aggregationLevel2: n0 (0)
// aggregationLevel4: n1 (1)
// aggregationLevel8: n0 (0)
// aggregationLevel16: n0 (0)
// searchSpaceType: common (0)
// common
// dci-Format0-0-AndFormat1-0
srsran_search_space_t search_space1 = {};
search_space1.id = 1;
search_space1.coreset_id = 1;
search_space1.nof_candidates[0] = 1;
search_space1.nof_candidates[1] = 1;
search_space1.nof_candidates[2] = 1;
search_space1.nof_candidates[3] = 0;
search_space1.nof_candidates[4] = 0;
search_space1.type = srsran_search_space_type_common_3;
pdcch.search_space[1] = search_space1;
pdcch.search_space_present[1] = true;
// ra-SearchSpace: 1
pdcch.ra_rnti = 0x16; //< Supposed to be deduced from PRACH configuration
pdcch.ra_search_space = search_space1;
pdcch.ra_search_space.type = srsran_search_space_type_common_1;
pdcch.ra_search_space_present = true;
// spCellConfigDedicated
// initialDownlinkBWP
// pdcch-Config: setup (1)
@ -135,32 +102,6 @@ struct phy_cfg_nr_t {
}
pdcch.coreset_present[2] = true;
// searchSpacesToAddModList: 1 item
// Item 0
// SearchSpace
// searchSpaceId: 2
// controlResourceSetId: 2
// monitoringSlotPeriodicityAndOffset: sl1 (0)
// sl1: NULL
// monitoringSymbolsWithinSlot: 8000 [bit length 14, 2 LSB pad bits, 1000 0000 0000
// 00.. decimal value 8192] nrofCandidates
// aggregationLevel1: n0 (0)
// aggregationLevel2: n2 (2)
// aggregationLevel4: n1 (1)
// aggregationLevel8: n0 (0)
// aggregationLevel16: n0 (0)
// searchSpaceType: ue-Specific (1)
// ue-Specific
// dci-Formats: formats0-0-And-1-0 (0)
pdcch.search_space[2].id = 2;
pdcch.search_space[2].coreset_id = 2;
pdcch.search_space[2].nof_candidates[0] = 0;
pdcch.search_space[2].nof_candidates[1] = 2;
pdcch.search_space[2].nof_candidates[2] = 1;
pdcch.search_space[2].nof_candidates[3] = 0;
pdcch.search_space[2].nof_candidates[4] = 0;
pdcch.search_space[2].type = srsran_search_space_type_ue;
pdcch.search_space_present[2] = true;
// pdsch-Config: setup (1)
// setup
// dmrs-DownlinkForPDSCH-MappingTypeA: setup (1)
@ -965,6 +906,71 @@ struct phy_cfg_nr_t {
csi.reports[0].freq_cfg = SRSRAN_CSI_REPORT_FREQ_WIDEBAND;
csi.reports[0].cqi_table = SRSRAN_CSI_CQI_TABLE_2;
}
/**
* @param carrier
*/
srsran_dci_cfg_nr_t get_dci_cfg(const srsran_carrier_nr_t& carrier) const
{
srsran_dci_cfg_nr_t dci_cfg = {};
// Set bandwidths
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;
// Format 0_1 specific configuration (for PUSCH only)
dci_cfg.nof_ul_bwp = 1;
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.nof_rb_groups = 1;
dci_cfg.pusch_alloc_type = pusch.alloc;
// Format 1_1 specific configuration (for PDSCH only)
dci_cfg.nof_dl_bwp = 1;
dci_cfg.pdsch_alloc_type = pdsch.alloc;
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;
return dci_cfg;
};
};
} // namespace srsran

@ -60,6 +60,7 @@ class gw_interface_rrc
public:
virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0;
virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0;
virtual bool is_running() = 0;
};
class gw_interface_pdcp

@ -53,7 +53,7 @@ public:
uint32_t pid;
uint16_t rnti;
uint32_t tti;
uint32_t tbs;
uint32_t tbs; // transport block size in Bytes
} mac_nr_grant_ul_t;
/// For UL, payload buffer remains in MAC
@ -102,6 +102,14 @@ public:
* @param ul_carrier_id The UL carrier used for Msg1 transmission (0 for NUL carrier, and 1 for SUL carrier).
*/
virtual void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) = 0;
/**
* @brief Indicate a valid SR transmission occasion on the valid PUCCH resource for SR configured; and the SR
* transmission occasion does not overlap with a measurement gap; and the PUCCH resource for the SR transmission
* occasion does not overlap with a UL-SCH resource;
* @param tti The TTI from the PHY viewpoint at which the SR occasion was sent over-the-air (not to the radio).
*/
virtual bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) = 0;
};
class mac_interface_rrc_nr
@ -124,13 +132,13 @@ public:
};
struct phy_args_nr_t {
uint32_t nof_carriers;
uint32_t nof_prb;
uint32_t nof_phy_threads;
uint32_t worker_cpu_mask;
srsran::phy_log_args_t log;
srsran_ue_dl_nr_args_t dl;
srsran_ue_ul_nr_args_t ul;
uint32_t nof_carriers = 1;
uint32_t nof_prb = 52;
uint32_t nof_phy_threads = 3;
uint32_t worker_cpu_mask = 0;
srsran::phy_log_args_t log = {};
srsran_ue_dl_nr_args_t dl = {};
srsran_ue_ul_nr_args_t ul = {};
std::set<uint32_t> fixed_sr = {1};
uint32_t fix_wideband_cqi = 15; // Set to a non-zero value for fixing the wide-band CQI report
@ -172,8 +180,17 @@ public:
const float preamble_received_target_power,
const float ta_base_sec = 0.0f) = 0;
/// Instruct PHY to transmit SR for a given identifier
virtual void sr_send(uint32_t sr_id) = 0;
/**
* @brief Query PHY if there is a valid PUCCH SR resource configured for a given SR identifier
* @param sr_id SR identifier
* @return True if there is a valid PUCCH resource configured
*/
virtual bool has_valid_sr_resource(uint32_t sr_id) = 0;
/**
* @brief Clear any configured downlink assignments and uplink grants
*/
virtual void clear_pending_grants() = 0;
};
class phy_interface_rrc_nr

@ -35,6 +35,7 @@ public:
virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1) = 0;
virtual void add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) = 0;
virtual void del_bearer(uint32_t lcid) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid, srsran::as_security_config_t sec_cfg) = 0;
virtual void config_security_all(srsran::as_security_config_t sec_cfg) = 0;

@ -43,6 +43,8 @@ class rrc_eutra_interface_rrc_nr
public:
virtual void new_cell_meas_nr(const std::vector<phy_meas_nr_t>& meas) = 0;
virtual void nr_rrc_con_reconfig_complete(bool status) = 0;
virtual void nr_notify_reconfiguration_failure() = 0;
virtual void nr_scg_failure_information(const srsran::scg_failure_cause_t cause) = 0;
};
class rrc_interface_phy_lte

@ -60,7 +60,10 @@ public:
PADDING = 0b111111,
} nr_lcid_sch_t;
mac_sch_subpdu_nr(mac_sch_pdu_nr* parent_);
// SDUs up to 256 B can use the short 8-bit L field
static const int32_t MAC_SUBHEADER_LEN_THRESHOLD = 256;
mac_sch_subpdu_nr(mac_sch_pdu_nr* parent_) : parent(parent_), logger(&srslog::fetch_basic_logger("MAC")){};
nr_lcid_sch_t get_type();
bool is_sdu();
@ -88,12 +91,20 @@ public:
static const uint8_t max_num_lcg_lbsr = 8;
std::array<lcg_bsr_t, max_num_lcg_lbsr> get_lbsr();
// TA
struct ta_t {
uint8_t tag_id;
uint8_t ta_command;
};
ta_t get_ta();
// setters
void set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
void set_padding(const uint32_t len_);
void set_c_rnti(const uint16_t crnti_);
void set_se_phr(const uint8_t phr_, const uint8_t pcmax_);
void set_sbsr(const lcg_bsr_t bsr_);
void set_lbsr(const std::array<mac_sch_subpdu_nr::lcg_bsr_t, max_num_lcg_lbsr> bsr_);
uint32_t write_subpdu(const uint8_t* start_);
@ -101,7 +112,8 @@ public:
static uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
private:
// protected:
srslog::basic_logger* logger;
uint32_t lcid = 0;
int header_length = 0;
int sdu_length = 0;
@ -129,11 +141,12 @@ public:
void init_rx(bool ulsch_ = false);
// Add SDU or CEs to PDU
// All functions will return SRSRAN_SUCCESS on success, and SRSLE_ERROR otherwise
// All functions will return SRSRAN_SUCCESS on success, and SRSRAN_ERROR otherwise
uint32_t add_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
uint32_t add_crnti_ce(const uint16_t crnti_);
uint32_t add_se_phr_ce(const uint8_t phr_, const uint8_t pcmax_);
uint32_t add_sbsr_ce(const mac_sch_subpdu_nr::lcg_bsr_t bsr_);
uint32_t add_lbsr_ce(const std::array<mac_sch_subpdu_nr::lcg_bsr_t, mac_sch_subpdu_nr::max_num_lcg_lbsr> bsr_);
uint32_t get_remaing_len();

@ -67,8 +67,8 @@ private:
} pdu_t;
static_blocking_queue<pdu_t*, DEFAULT_POOL_SIZE> pdu_q;
buffer_pool<pdu_t> pool;
static_blocking_queue<pdu_t*, DEFAULT_POOL_SIZE> pdu_q;
process_callback* callback;
srslog::basic_logger& logger;

@ -122,7 +122,7 @@ extern "C" {
* @brief Maximum number of PDSCH time domain resource allocations. This is defined by TS 38.331 v15.10.0
* as maxNrofDL-Allocations
*/
#define SRSRAN_MAX_NOF_DL_ALLOCATION 16
#define SRSRAN_MAX_NOF_TIME_RA 16
/**
* @brief Maximum dl-DataToUL-ACK value. This is defined by TS 38.331 v15.10.1 in PUCCH-Config
@ -152,7 +152,7 @@ typedef enum SRSRAN_API {
typedef enum SRSRAN_API { srsran_sch_mapping_type_A = 0, srsran_sch_mapping_type_B } srsran_sch_mapping_type_t;
/**
* @brief Search spaces
* @brief Search Space (SS) type
* @remark Described in TS 38.213 V15.10.0 Section 10.1 UE procedure for determining physical downlink control channel
* assignment
*/
@ -218,7 +218,8 @@ typedef enum SRSRAN_API {
srsran_dci_format_nr_2_2, ///< @brief Transmission of TPC commands for PUCCH and PUSCH
srsran_dci_format_nr_2_3, ///< @brief Transmission of a group of TPC commands for SRS transmissions by one or more UEs
srsran_dci_format_nr_rar, ///< @brief Scheduling a transmission of PUSCH from RAR
srsran_dci_format_nr_cg ///< @brief Scheduling of PUSCH using a configured grant
srsran_dci_format_nr_cg, ///< @brief Scheduling of PUSCH using a configured grant
SRSRAN_DCI_FORMAT_NR_COUNT ///< @brief Number of DCI formats
} srsran_dci_format_nr_t;
/**
@ -241,7 +242,18 @@ typedef enum SRSRAN_API {
srsran_pdsch_harq_ack_codebook_none = 0,
srsran_pdsch_harq_ack_codebook_semi_static,
srsran_pdsch_harq_ack_codebook_dynamic,
} srsran_pdsch_harq_ack_codebook_t;
} srsran_harq_ack_codebook_t;
/**
* @brief PDSCH/PUSCH Resource allocation configuration
* @remark Described in TS 38.331 V15.10.0 PhysicalCellGroupConfig
*/
typedef enum SRSRAN_API {
srsran_resource_alloc_type0 = 0,
srsran_resource_alloc_type1,
srsran_resource_alloc_dynamic,
} srsran_resource_alloc_t;
/**
* @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
*/
@ -312,8 +324,10 @@ typedef struct SRSRAN_API {
typedef struct SRSRAN_API {
uint32_t id;
uint32_t coreset_id;
uint32_t duration; // in slots
srsran_search_space_type_t type;
uint32_t duration; ///< SS duration length in slots
srsran_search_space_type_t type; ///< Sets the SS type, common (multiple types) or UE specific
srsran_dci_format_nr_t formats[SRSRAN_DCI_FORMAT_NR_COUNT]; ///< Specifies the DCI formats that shall be searched
uint32_t nof_formats;
uint32_t nof_candidates[SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR];
} srsran_search_space_t;
@ -343,6 +357,13 @@ typedef struct SRSRAN_API {
*/
SRSRAN_API const char* srsran_rnti_type_str(srsran_rnti_type_t rnti_type);
/**
* @brief Get the RNTI type name for NR
* @param rnti_type RNTI type name
* @return Constant string with the RNTI type name
*/
SRSRAN_API const char* srsran_dci_format_nr_string(srsran_dci_format_nr_t format);
/**
* @brief Calculates the bandwidth of a given CORESET in physical resource blocks (PRB) . This function uses the
* frequency domain resources bit-map for counting the number of PRB.

@ -24,6 +24,7 @@
#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"
@ -38,7 +39,7 @@ typedef struct SRSRAN_API {
uint32_t max_prb;
uint32_t nof_tx_antennas;
srsran_carrier_nr_t carrier;
srsran_coreset_t coreset;
srsran_pdcch_cfg_nr_t pdcch_cfg;
srsran_ofdm_t fft[SRSRAN_MAX_PORTS];
@ -46,6 +47,7 @@ typedef struct SRSRAN_API {
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;
@ -54,7 +56,9 @@ srsran_enb_dl_nr_init(srsran_enb_dl_nr_t* q, cf_t* output[SRSRAN_MAX_PORTS], con
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_coreset(srsran_enb_dl_nr_t* q, const srsran_coreset_t* coreset);
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);

@ -135,19 +135,6 @@ srsran_ldpc_decoder_decode_f(srsran_ldpc_decoder_t* q, const float* llrs, uint8_
SRSRAN_API int
srsran_ldpc_decoder_decode_s(srsran_ldpc_decoder_t* q, const int16_t* llrs, uint8_t* message, uint32_t cdwd_rm_length);
/*!
* Carries out the actual decoding with 8-bit integer-valued LLRs. It is
* recommended to use a 7-bit representation for the LLRs, given that all
* values exceeding \f$ 2^{7}-1 \f$ (in magnitude) will be considered as infinity.
* \param[in] q A pointer to the LDPC decoder (a srsran_ldpc_decoder_t structure
* instance) that carries out the decoding.
* \param[in] llrs The LLRs obtained from the channel samples that correspond to
* the codeword to be decoded.
* \param[out] message The message (uncoded bits) resulting from the decoding
* operation.
*/
SRSRAN_API int srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q, const int8_t* llrs, uint8_t* message);
/*!
* Carries out the actual decoding with 8-bit integer-valued LLRs. It is
* recommended to use a 7-bit representation for the LLRs, given that all
@ -160,9 +147,7 @@ SRSRAN_API int srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q, const int8
* operation.
* \param[in] cdwd_rm_length The number of bits forming the codeword (after rate matching).
*/
SRSRAN_API int srsran_ldpc_decoder_decode_rm_c(srsran_ldpc_decoder_t* q,
const int8_t* llrs,
uint8_t* message,
uint32_t cdwd_rm_length);
SRSRAN_API int
srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q, const int8_t* llrs, uint8_t* message, uint32_t cdwd_rm_length);
#endif // SRSRAN_LDPCDECODER_H

@ -178,7 +178,7 @@ SRSRAN_API int srsran_ldpc_rm_rx_init_c(srsran_ldpc_rm_t* q);
* \param[in] rv Redundancy version 0,1,2,3.
* \param[in] mod_type Modulation type.
* \param[in] Nref Size of limited buffer.
* \return An integer: 0 if the function executes correctly, -1 otherwise.
* \return An integer: The number of useful LLR if the function executes correctly, -1 otherwise.
*/
SRSRAN_API int srsran_ldpc_rm_rx_c(srsran_ldpc_rm_t* q,
const int8_t* input,

@ -26,24 +26,131 @@
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/phch/phch_cfg_nr.h"
/**
* @brief Maximum number of NR DCI sizes the UE shall search for a given serving cell
*/
#define SRSRAN_DCI_NR_MAX_NOF_SIZES 4
/**
* @brief DCI configuration given a serving cell
*/
typedef struct SRSRAN_API {
/// Bandwidth parameters
uint32_t coreset0_bw; ///< CORESET0 DL bandwidth, set to 0 if not present
uint32_t bwp_dl_initial_bw; ///< Initial DL BWP bandwidth
uint32_t bwp_dl_active_bw; ///< Active DL BWP bandwidth in PRB
uint32_t bwp_ul_initial_bw; ///< Initial UL BWP bandwidth
uint32_t bwp_ul_active_bw; ///< Active UL BWP bandwidth in PRB
/// Search space derived parameters
bool monitor_common_0_0; ///< Set to true if Format 0_0 is monitored in common SS
bool monitor_0_0_and_1_0; ///< Set to true if Format 0_0 is monitored in UE-specific SS
bool monitor_0_1_and_1_1; ///< Set to true if Formats 0_1 and 1_1 are monitored in UE-specific SS
/// PUSCH configuration derived parameters
bool enable_sul; ///< Set to true if supplementary uplink is configured
bool enable_hopping; ///< Set to true if frequency hopping is enabled
/// Common Formats 0_1 and 1_1
uint32_t carrier_indicator_size; ///< Defined in TS 38.213 clause 10.1
srsran_harq_ack_codebook_t harq_ack_codebok; ///< PDSCH HARQ-ACK codebook mode
uint32_t nof_rb_groups; ///< Defined in TS 38.214 clause 6.1.2.2.1
/// Format 0_1 specific configuration (for PUSCH only)
uint32_t nof_ul_bwp; ///< Number of UL BWPs excluding the initial UL BWP, mentioned in the TS as N_BWP_RRC
uint32_t nof_ul_time_res; ///< Number of dedicated PUSCH time domain resource assigment, set to 0 for default
uint32_t nof_srs; ///< Number of configured SRS resources
uint32_t nof_ul_layers; ///< Set to the maximum number of layers for PUSCH
uint32_t pusch_nof_cbg; ///< determined by maxCodeBlockGroupsPerTransportBlock for PUSCH
uint32_t report_trigger_size; ///< determined by reportTriggerSize
bool enable_transform_precoding; ///< Set to true if PUSCH transform precoding is enabled
bool dynamic_dual_harq_ack_codebook; ///< Set to true if HARQ-ACK codebook is set to dynamic with 2 sub-codebooks
bool pusch_tx_config_codebook; ///< Set to true if PUSCH txConfig is set to codebook
bool pusch_dmrs_type2; ///< Set to true if PUSCH DMRS are type 2
bool pusch_dmrs_double; ///< Set to true if PUSCH DMRS are 2 symbol long
bool pusch_ptrs; ///< Set to true if PT-RS are enabled for PUSCH transmission
bool pusch_dynamic_betas; ///< Set to true if beta offsets operation is not semi-static
srsran_resource_alloc_t pusch_alloc_type; ///< PUSCH resource allocation type
/// Format 1_1 specific configuration (for PDSCH only)
uint32_t nof_dl_bwp; ///< Number of DL BWPs excluding the initial UL BWP, mentioned in the TS as N_BWP_RRC
srsran_resource_alloc_t pdsch_alloc_type; ///< PDSCH resource allocation type, set to 0 for default
uint32_t nof_dl_time_res; ///< Number of dedicated PDSCH time domain resource assigment
uint32_t nof_aperiodic_zp; ///< Number of aperiodic ZP CSI-RS resource sets configured
bool pdsch_inter_prb_to_prb; ///< Set to true if interleaved VRB to PRB mapping is enabled
bool pdsch_rm_pattern1; ///< Set to true if rateMatchPatternGroup1 is configured
bool pdsch_rm_pattern2; ///< Set to true if rateMatchPatternGroup2 is configured
bool pdsch_2cw; ///< Set to true if maxNrofCodeWordsScheduledByDCI is set to 2 in any BWP
uint32_t pdsch_nof_cbg; ///< determined by maxCodeBlockGroupsPerTransportBlock for PDSCH
bool multiple_scell; ///< Set to true if configured with multiple serving cell
bool nof_dl_to_ul_ack; ///< Number of entries in the dl-DataToUL-ACK
bool pdsch_dmrs_type2; ///< Set to true if PDSCH DMRS are type 2
bool pdsch_dmrs_double; ///< Set to true if PDSCH DMRS are 2 symbol long
bool pdsch_tci; ///< Set to true if tci-PresentInDCI is enabled
bool pdsch_cbg_flush; ///< Set to true if codeBlockGroupFlushIndicator is true
bool pdsch_dynamic_bundling; ///< Set to true if prb-BundlingType is set to dynamicBundling
} srsran_dci_cfg_nr_t;
/**
* @brief NR-DCI object. Stores DCI configuration and pre-calculated DCI sizes
*/
typedef struct SRSRAN_API {
/// Configuration parameters
srsran_dci_cfg_nr_t cfg;
/// Formats 0_0 and 1_0 in common SS
uint32_t dci_0_0_and_1_0_common_size; ///< DCI format 0_0 and 1_0 in common SS size
uint32_t dci_0_0_common_trunc; ///< DCI format 0_0 in common SS truncation
uint32_t dci_0_0_common_padd; ///< DCI format 0_0 in common SS padding
/// Formats 0_0 and 1_0 in UE-specific SS
uint32_t dci_0_0_and_1_0_ue_size; ///< DCI format 0_0 and 1_0 in UE-specific SS size
uint32_t dci_0_0_ue_padd; ///< DCI format 0_0 in ue SS padding
uint32_t dci_1_0_ue_padd; ///< DCI format 1_0 in ue SS padding
/// Formats 0_1 and 1_0 (UE-specific SS only)
uint32_t dci_0_1_size; ///< DCI format 0_1 size
uint32_t dci_0_1_padd; ///< DCI format 0_1 padding
uint32_t dci_1_1_size; ///< DCI format 0_1 size
uint32_t dci_1_1_padd; ///< DCI format 1_1 padding
} srsran_dci_nr_t;
/**
* @brief Describes the NR DCI search context
*/
typedef struct SRSRAN_API {
srsran_dci_location_t location; ///< DCI location
srsran_search_space_type_t ss_type; ///< Search space type
uint32_t coreset_id; ///< CORESET identifier
srsran_rnti_type_t rnti_type; ///< RNTI type
srsran_dci_format_nr_t format; ///< DCI format
uint16_t rnti; ///< UE temporal RNTI
uint32_t coreset0_bw; ///< CORESET0 DL bandwidth, set to 0 if not present
uint32_t bwp_dl_initial_bw; ///< Initial DL/UL BWP bandwidth
uint32_t bwp_dl_active_bw; ///< Active DL/UL BWP bandwidth in PRB
uint32_t bwp_ul_initial_bw; ///< Initial UL BWP bandwidth
uint32_t bwp_ul_active_bw; ///< Active UL BWP bandwidth in PRB
bool monitor_common_0_0; ///< Set to true if Format 0_0 is monitored in common SS
bool enable_sul; ///< Set to true if supplementary uplink is configured
bool enable_hopping; ///< Set to true if frequency hopping is enabled
} srsran_dci_ctx_t;
/**
* @brief Describes any packed format NR DCI message
*/
typedef struct SRSRAN_API {
srsran_dci_location_t location;
srsran_search_space_type_t search_space;
uint32_t coreset_id;
srsran_dci_ctx_t ctx; ///< DCI context
uint8_t payload[50];
srsran_rnti_type_t rnti_type;
uint32_t nof_bits;
srsran_dci_format_nr_t format;
uint16_t rnti;
} srsran_dci_msg_nr_t;
/**
* @brief Describes an unpacked DL NR DCI message
*/
typedef struct SRSRAN_API {
uint16_t rnti;
srsran_rnti_type_t rnti_type;
srsran_dci_format_nr_t format;
srsran_dci_location_t location;
srsran_search_space_type_t search_space;
uint32_t coreset_id;
srsran_dci_ctx_t ctx; ///< DCI search context
// Common fields
uint32_t freq_domain_assigment; ///< Frequency domain resource assignment
@ -71,14 +178,13 @@ typedef struct SRSRAN_API {
} srsran_dci_dl_nr_t;
/**
* @brief Describes an unpacked UL NR DCI message
* @remark NR RAR UL DCI Described in TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
*/
typedef struct SRSRAN_API {
// Context information
uint16_t rnti;
srsran_rnti_type_t rnti_type;
srsran_dci_format_nr_t format;
srsran_dci_location_t location;
srsran_search_space_type_t search_space;
uint32_t coreset_id;
srsran_dci_ctx_t ctx; ///< Context information
// Common fields
uint32_t freq_domain_assigment; ///< Frequency domain resource assignment
@ -100,60 +206,93 @@ typedef struct SRSRAN_API {
// Random Access Response Grant
uint32_t csi_request;
// Other fields
uint32_t sul; ///< Supplementary Uplink flag
} srsran_dci_ul_nr_t;
/**
* @brief Indicates whether the provided DCI message format bit indicator belongs to DCI format 1_0 according according
* to the RNTI type. If invalid, the DCI message is likely to be format 0_0
* @param dci_msg Provides DCI format 1_0 message
* @return true if the DCI message is format 1_0, false otherwise
* @brief Set NR-DCI configuration for a given cell. This function will pre-compute the DCI sizes, padding, truncation
* and so on from a given DCI configuration.
* @remark Implemented according TS 38.212 section 7.3.1.0 DCI size alignment
* @param[in,out] dci DCI object
* @param[in] cfg NR-DCI configuration
* @return SRSLTE_SUCCESS if the configuration is valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API bool srsran_dci_nr_format_1_0_valid(const srsran_dci_msg_nr_t* dci_msg);
SRSRAN_API int srsran_dci_nr_set_cfg(srsran_dci_nr_t* dci, const srsran_dci_cfg_nr_t* cfg);
SRSRAN_API int srsran_dci_nr_pack(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
const srsran_dci_dl_nr_t* dci,
srsran_dci_msg_nr_t* msg);
SRSRAN_API int srsran_dci_nr_format_0_0_sizeof(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
srsran_rnti_type_t rnti_type);
/**
* @brief Calculates a DL NR-DCI size for a given SS type and format
* @attention Only DCI 0_0 and 1_0 can be in common search-space
* @param q NR DCI object
* @param ss_type Search Space type
* @param format NR DCI format
* @return The number of bis for the DCI message if configured, 0 otherwise
*/
SRSRAN_API uint32_t srsran_dci_nr_size(const srsran_dci_nr_t* q,
srsran_search_space_type_t ss_type,
srsran_dci_format_nr_t format);
SRSRAN_API int srsran_dci_nr_format_0_0_pack(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset0,
const srsran_dci_ul_nr_t* dci,
srsran_dci_msg_nr_t* msg);
/**
* @brief Indicates whether the provided DCI message format bit indicator belongs to the a Dl DCI format (1_0 or 1_1)
* according according to the RNTI type. If invalid, the DCI message is likely to be an UL DCI
* @param dci Provides DCI format message
* @return true if the DCI message is for DL, false otherwise
*/
SRSRAN_API bool srsran_dci_nr_valid_direction(const srsran_dci_msg_nr_t* dci);
SRSRAN_API int srsran_dci_nr_format_0_0_unpack(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
srsran_dci_msg_nr_t* msg,
srsran_dci_ul_nr_t* dci);
/**
* @brief Packs a DL NR DCI into a DCI message
* @param q NR DCI object with precomputed DCI parameters
* @param dci DL NR DCI to pack (serialize)
* @param[out] msg Resultant packed DCI message
* @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg);
/**
* @brief Unpacks DCI from Random Access Response Grant
* @remark Described in TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
* @param msg
* @param dci
* @return SRSRAN_SUCCESS if unpacked correctly, SRSRAN_ERROR code otherwise
* @brief Unpacks an NR DCI message into a DL NR DCI
* @param q NR DCI object with precomputed DCI parameters
* @param msg DCI message to unpack (deserialize)
* @param[out] dci Resultant unpacked DL DCI
* @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_dci_nr_rar_unpack(srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci);
SRSRAN_API int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci);
SRSRAN_API int srsran_dci_nr_format_1_0_sizeof(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
srsran_rnti_type_t rnti_type);
/**
* @brief Packs an UL NR DCI into a DCI message
* @param q NR DCI object with precomputed DCI parameters
* @param dci UL NR DCI to pack (serialize)
* @param[out] msg resultant DCI message
* @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg);
SRSRAN_API int srsran_dci_nr_format_1_0_pack(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
const srsran_dci_dl_nr_t* dci,
srsran_dci_msg_nr_t* msg);
/**
* @brief Unpacks an NR DCI message into an UL NR DCI
* @param q NR DCI object with precomputed DCI parameters
* @param msg DCI message to unpack (deserialize)
* @param[out] dci Resultant unpacked UL DCI
* @return SRSLTE_SUCCESS if provided arguments are valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci);
SRSRAN_API int srsran_dci_nr_format_1_0_unpack(const srsran_carrier_nr_t* carrier,
const srsran_coreset_t* coreset,
srsran_dci_msg_nr_t* msg,
srsran_dci_dl_nr_t* dci);
/**
* @brief Stringifies an DL NR DCI structure
* @param dci DL NR SCI structure to stringify
* @param[out] str Destination string
* @param str_len Destination string length
* @return The number of written characters
*/
SRSRAN_API int srsran_dci_dl_nr_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
/**
* @brief Stringifies an UL NR DCI structure
* @param dci UL NR SCI structure to stringify
* @param[out] str Destination string
* @param str_len Destination string length
* @return The number of written characters
*/
SRSRAN_API int srsran_dci_ul_nr_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len);
SRSRAN_API int srsran_dci_dl_nr_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
#endif // SRSRAN_DCI_NR_H

@ -0,0 +1,44 @@
/**
*
* \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_PDCCH_CFG_NR_H
#define SRSRAN_PDCCH_CFG_NR_H
#include "dci_nr.h"
/**
* Maximum number of CORESET
* @remark Defined in TS 38.331 by maxNrofControlResourceSets-1
*/
#define SRSRAN_UE_DL_NR_MAX_NOF_CORESET 12
/**
* Maximum number of Search spaces
* @remark Defined in TS 38.331 by maxNrofSearchSpaces-1
*/
#define SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE 40
/**
* @brief PDCCH configuration provided by upper layers
*/
typedef struct SRSRAN_API {
srsran_coreset_t coreset[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< PDCCH Control resource sets (CORESET) collection
bool coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< CORESET present flags
srsran_search_space_t search_space[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE];
bool search_space_present[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE];
srsran_search_space_t ra_search_space;
bool ra_search_space_present;
} srsran_pdcch_cfg_nr_t;
#endif // SRSRAN_PDCCH_CFG_NR_H

@ -210,13 +210,14 @@ typedef struct SRSRAN_API {
bool present;
} dmrs_typeB;
srsran_sch_time_ra_t common_time_ra[SRSRAN_MAX_NOF_DL_ALLOCATION];
srsran_sch_time_ra_t common_time_ra[SRSRAN_MAX_NOF_TIME_RA];
uint32_t nof_common_time_ra;
srsran_sch_time_ra_t dedicated_time_ra[SRSRAN_MAX_NOF_DL_ALLOCATION];
srsran_sch_time_ra_t dedicated_time_ra[SRSRAN_MAX_NOF_TIME_RA];
uint32_t nof_dedicated_time_ra;
bool rbg_size_cfg_1; ///< RBG size configuration (1 or 2)
srsran_resource_alloc_t alloc;
srsran_sch_cfg_t sch_cfg; ///< Common shared channel parameters

@ -26,22 +26,11 @@
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/dft/ofdm.h"
#include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/phch/pdcch_cfg_nr.h"
#include "srsran/phy/phch/pdcch_nr.h"
#include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/phch/uci_cfg_nr.h"
/**
* Maximum number of CORESET
* @remark Defined in TS 38.331 by maxNrofControlResourceSets-1
*/
#define SRSRAN_UE_DL_NR_MAX_NOF_CORESET 12
/**
* Maximum number of Search spaces
* @remark Defined in TS 38.331 by maxNrofSearchSpaces-1
*/
#define SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE 40
/**
* Maximum number of DCI messages to receive
*/
@ -56,18 +45,6 @@ typedef struct SRSRAN_API {
float pdcch_dmrs_epre_thr;
} srsran_ue_dl_nr_args_t;
typedef struct SRSRAN_API {
srsran_coreset_t coreset[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< PDCCH Control resource sets (CORESET) collection
bool coreset_present[SRSRAN_UE_DL_NR_MAX_NOF_CORESET]; ///< CORESET present flags
srsran_search_space_t search_space[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE];
bool search_space_present[SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE];
uint16_t ra_rnti; ///< Needs to be deduced from the PRACH configuration
srsran_search_space_t ra_search_space;
bool ra_search_space_present;
} srsran_ue_dl_nr_pdcch_cfg_t;
typedef struct {
uint32_t scell_idx; ///< Serving cell index
uint32_t v_dai_dl; ///< Downlink Assigment Index
@ -104,7 +81,7 @@ typedef struct {
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_pdsch_harq_ack_codebook_t pdsch_harq_ack_codebook; ///< pdsch-HARQ-ACK-Codebook configuration
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];
@ -112,11 +89,10 @@ typedef struct SRSRAN_API {
} srsran_ue_dl_nr_harq_ack_cfg_t;
typedef struct SRSRAN_API {
uint32_t coreset_id;
uint32_t ss_id;
srsran_dci_location_t location;
srsran_dci_ctx_t dci_ctx;
srsran_dmrs_pdcch_measure_t measure;
srsran_pdcch_nr_res_t result;
uint32_t nof_bits;
} srsran_ue_dl_nr_pdcch_info_t;
typedef struct SRSRAN_API {
@ -126,7 +102,7 @@ typedef struct SRSRAN_API {
float pdcch_dmrs_epre_thr;
srsran_carrier_nr_t carrier;
srsran_ue_dl_nr_pdcch_cfg_t cfg;
srsran_pdcch_cfg_nr_t cfg;
srsran_ofdm_t fft[SRSRAN_MAX_PORTS];
@ -143,12 +119,15 @@ typedef struct SRSRAN_API {
srsran_ue_dl_nr_pdcch_info_t pdcch_info[SRSRAN_MAX_NOF_CANDIDATES_SLOT_NR];
uint32_t pdcch_info_count;
/// DCI packing/unpacking object
srsran_dci_nr_t dci;
/// Temporally stores Found DCI messages from all SS
srsran_dci_msg_nr_t dci_msg[SRSRAN_MAX_DCI_MSG_NR];
uint32_t dci_msg_count;
srsran_dci_msg_nr_t dl_dci_msg[SRSRAN_MAX_DCI_MSG_NR];
uint32_t dl_dci_msg_count;
srsran_dci_msg_nr_t pending_ul_dci_msg[SRSRAN_MAX_DCI_MSG_NR];
uint32_t pending_ul_dci_count;
srsran_dci_msg_nr_t ul_dci_msg[SRSRAN_MAX_DCI_MSG_NR];
uint32_t ul_dci_count;
} srsran_ue_dl_nr_t;
SRSRAN_API int
@ -156,7 +135,9 @@ srsran_ue_dl_nr_init(srsran_ue_dl_nr_t* q, cf_t* input[SRSRAN_MAX_PORTS], const
SRSRAN_API int srsran_ue_dl_nr_set_carrier(srsran_ue_dl_nr_t* q, const srsran_carrier_nr_t* carrier);
SRSRAN_API int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr_pdcch_cfg_t* cfg);
SRSRAN_API int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q,
const srsran_pdcch_cfg_nr_t* cfg,
const srsran_dci_cfg_nr_t* dci_cfg);
SRSRAN_API void srsran_ue_dl_nr_free(srsran_ue_dl_nr_t* q);
@ -195,4 +176,8 @@ 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, 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);
#endif // SRSRAN_UE_DL_NR_H

@ -0,0 +1,27 @@
/**
*
* \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_BEARER_MEM_POOL_H
#define SRSRAN_BEARER_MEM_POOL_H
#include <cstddef>
namespace srsran {
// Allocation of objects in rnti-dedicated memory pool
void reserve_rlc_memblocks(size_t nof_blocks);
void* allocate_rlc_bearer(std::size_t size);
void deallocate_rlc_bearer(void* p);
} // namespace srsran
#endif // SRSRAN_BEARER_MEM_POOL_H

@ -49,7 +49,7 @@ public:
void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu);
void add_bearer(uint32_t lcid, pdcp_config_t cnfg) override;
void add_bearer_mrb(uint32_t lcid, pdcp_config_t cnfg);
void del_bearer(uint32_t lcid);
void del_bearer(uint32_t lcid) override;
void change_lcid(uint32_t old_lcid, uint32_t new_lcid) override;
void config_security(uint32_t lcid, as_security_config_t sec_cfg) override;
void config_security_all(as_security_config_t sec_cfg) override;

@ -65,6 +65,7 @@ public:
pdcp_entity_base(task_sched_handle task_sched_, srslog::basic_logger& logger);
pdcp_entity_base(pdcp_entity_base&&) = default;
virtual ~pdcp_entity_base();
virtual bool configure(const pdcp_config_t& cnfg_) = 0;
virtual void reset() = 0;
virtual void reestablish() = 0;

@ -117,9 +117,9 @@ public:
srsue::gw_interface_pdcp* gw_,
srsran::task_sched_handle task_sched_,
srslog::basic_logger& logger,
uint32_t lcid_,
pdcp_config_t cfg_);
uint32_t lcid_);
~pdcp_entity_lte() override;
bool configure(const pdcp_config_t& cnfg_) override;
void reset() override;
void reestablish() override;

@ -48,9 +48,9 @@ public:
srsue::gw_interface_pdcp* gw_,
srsran::task_sched_handle task_sched_,
srslog::basic_logger& logger,
uint32_t lcid,
pdcp_config_t cfg_);
uint32_t lcid);
~pdcp_entity_nr() final;
bool configure(const pdcp_config_t& cnfg_) final;
void reset() final;
void reestablish() final;

@ -24,6 +24,7 @@
#include "srsran/adt/accumulators.h"
#include "srsran/adt/circular_array.h"
#include "srsran/adt/circular_map.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h"
#include "srsran/common/srsran_assert.h"
@ -82,53 +83,39 @@ struct pdcp_sdu_info_t {
template <class T>
struct rlc_ringbuffer_t {
rlc_ringbuffer_t() { clear(); }
T& add_pdu(size_t sn)
{
srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn);
window.overwrite(sn, T{});
window[sn].rlc_sn = sn;
active_flag[sn] = true;
count++;
return window[sn];
}
void remove_pdu(size_t sn)
{
srsran_expect(has_sn(sn), "The removed SN=%zd is not in the window", sn);
window[sn] = {};
active_flag[sn] = false;
count--;
}
T& operator[](size_t sn)
{
srsran_expect(has_sn(sn), "The accessed SN=%zd is not in the window", sn);
return window[sn];
}
size_t size() const { return count; }
bool empty() const { return count == 0; }
void clear()
{
std::fill(active_flag.begin(), active_flag.end(), false);
count = 0;
window.erase(sn);
}
T& operator[](size_t sn) { return window[sn]; }
size_t size() const { return window.size(); }
bool empty() const { return window.empty(); }
void clear() { window.clear(); }
bool has_sn(uint32_t sn) const { return active_flag[sn] and (window[sn].rlc_sn == sn); }
bool has_sn(uint32_t sn) const { return window.contains(sn); }
// Return the sum data bytes of all active PDUs (check PDU is non-null)
uint32_t get_buffered_bytes()
{
uint32_t buff_size = 0;
for (const auto& pdu : window) {
if (pdu.buf != nullptr) {
buff_size += pdu.buf->N_bytes;
if (pdu.second.buf != nullptr) {
buff_size += pdu.second.buf->N_bytes;
}
}
return buff_size;
}
private:
size_t count = 0;
srsran::circular_array<bool, RLC_AM_WINDOW_SIZE> active_flag = {};
srsran::circular_array<T, RLC_AM_WINDOW_SIZE> window;
srsran::static_circular_map<uint32_t, T, RLC_AM_WINDOW_SIZE> window;
};
struct buffered_pdcp_pdu_list {
@ -138,13 +125,20 @@ public:
void add_pdcp_sdu(uint32_t sn)
{
assert(not has_pdcp_sn(sn));
srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice");
uint32_t sn_idx = get_idx(sn);
if (buffered_pdus[sn_idx].sn != invalid_sn) {
clear_pdcp_sdu(buffered_pdus[sn_idx].sn);
}
buffered_pdus[get_idx(sn)].sn = sn;
count++;
}
void clear_pdcp_sdu(uint32_t sn)
{
uint32_t sn_idx = get_idx(sn);
if (buffered_pdus[sn_idx].sn == invalid_sn) {
return;
}
buffered_pdus[sn_idx].sn = invalid_sn;
buffered_pdus[sn_idx].fully_acked = false;
buffered_pdus[sn_idx].fully_txed = false;

@ -24,6 +24,7 @@
#include "srsran/adt/circular_buffer.h"
#include "srsran/interfaces/rlc_interface_types.h"
#include "srsran/upper/bearer_mem_pool.h"
#include "srsran/upper/rlc_metrics.h"
#include <stdlib.h>
@ -279,6 +280,9 @@ public:
virtual void set_bsr_callback(bsr_callback_t callback) = 0;
void* operator new(size_t sz) { return allocate_rlc_bearer(sz); }
void operator delete(void* p) { return deallocate_rlc_bearer(p); }
private:
bool suspended = false;

@ -277,13 +277,13 @@ bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg,
srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg;
switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) {
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value:
srsran_ue_dl_nr_harq_ack_cfg.pdsch_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;
break;
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::semi_static:
srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_semi_static;
srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_semi_static;
break;
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::nulltype:
srsran_ue_dl_nr_harq_ack_cfg.pdsch_harq_ack_codebook = srsran_pdsch_harq_ack_codebook_none;
srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_none;
break;
default:
asn1::log_warning("Invalid option for pdsch_harq_ack_codebook %s",
@ -321,9 +321,51 @@ bool make_phy_search_space_cfg(const search_space_s& search_space, srsran_search
switch (search_space.search_space_type.type()) {
case search_space_s::search_space_type_c_::types_opts::options::common:
srsran_search_space.type = srsran_search_space_type_common_3;
// dci-Format0-0-AndFormat1-0
// If configured, the UE monitors the DCI formats 0_0 and 1_0 according to TS 38.213 [13], clause 10.1.
if (search_space.search_space_type.common().dci_format0_minus0_and_format1_minus0_present) {
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_0;
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_0;
}
// dci-Format2-0
// If configured, UE monitors the DCI format 2_0 according to TS 38.213 [13], clause 10.1, 11.1.1.
if (search_space.search_space_type.common().dci_format2_minus0_present) {
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_0;
}
// dci-Format2-1
// If configured, UE monitors the DCI format 2_1 according to TS 38.213 [13], clause 10.1, 11.2.
if (search_space.search_space_type.common().dci_format2_minus1_present) {
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_1;
}
// dci-Format2-2
// If configured, UE monitors the DCI format 2_2 according to TS 38.213 [13], clause 10.1, 11.3.
if (search_space.search_space_type.common().dci_format2_minus2_present) {
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_2;
}
// dci-Format2-3
// If configured, UE monitors the DCI format 2_3 according to TS 38.213 [13], clause 10.1, 11.4
if (search_space.search_space_type.common().dci_format2_minus3_present) {
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_2_3;
}
break;
case search_space_s::search_space_type_c_::types_opts::options::ue_specific:
srsran_search_space.type = srsran_search_space_type_ue;
switch (search_space.search_space_type.ue_specific().dci_formats.value) {
case search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_e_::formats0_minus0_and_minus1_minus0:
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_0;
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_0;
break;
case search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_e_::formats0_minus1_and_minus1_minus1:
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_0_1;
srsran_search_space.formats[srsran_search_space.nof_formats++] = srsran_dci_format_nr_1_1;
break;
}
break;
default:
asn1::log_warning("Invalid option for search_space_type %s", search_space.search_space_type.type().to_string());

@ -37,7 +37,7 @@ uint32_t mac_pcap_net::open(std::string client_ip_addr_,
{
std::lock_guard<std::mutex> lock(mutex);
if (socket.is_init()) {
if (socket.is_open()) {
logger.error("PCAP socket writer for %s already running. Close first.", bind_addr_str.c_str());
return SRSRAN_ERROR;
}
@ -48,7 +48,7 @@ uint32_t mac_pcap_net::open(std::string client_ip_addr_,
return SRSRAN_ERROR;
}
if (not socket.bind_addr(bind_addr_str.c_str(), bind_udp_port_)) {
socket.reset();
socket.close();
logger.error("Couldn't bind socket %s to write PCAP", bind_addr_str.c_str());
return SRSRAN_ERROR;
}
@ -73,7 +73,7 @@ uint32_t mac_pcap_net::close()
{
{
std::lock_guard<std::mutex> lock(mutex);
if (running == false || socket.is_init() == false) {
if (running == false || socket.is_open() == false) {
return SRSRAN_ERROR;
}
@ -85,7 +85,7 @@ uint32_t mac_pcap_net::close()
wait_thread_finish();
// close socket handle
if (socket.is_init()) {
if (socket.is_open()) {
std::lock_guard<std::mutex> lock(mutex);
socket.close();
}
@ -95,7 +95,7 @@ uint32_t mac_pcap_net::close()
void mac_pcap_net::write_pdu(pcap_pdu_t& pdu)
{
if (pdu.pdu != nullptr && socket.is_init()) {
if (pdu.pdu != nullptr && socket.is_open()) {
switch (pdu.rat) {
case srsran_rat_t::lte:
write_mac_lte_pdu_to_net(pdu);

@ -24,11 +24,12 @@
#include <netinet/sctp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // for the pipe
#define rxSockError(fmt, ...) logger.error("%s: " fmt, name.c_str(), ##__VA_ARGS__)
#define rxSockWarn(fmt, ...) logger.warning("%s: " fmt, name.c_str(), ##__VA_ARGS__)
#define rxSockInfo(fmt, ...) logger.info("%s: " fmt, name.c_str(), ##__VA_ARGS__)
#define rxSockDebug(fmt, ...) logger.debug("%s: " fmt, name.c_str(), ##__VA_ARGS__)
#define rxSockError(fmt, ...) logger.error("RxSockets: " fmt, ##__VA_ARGS__)
#define rxSockWarn(fmt, ...) logger.warning("RxSockets: " fmt, ##__VA_ARGS__)
#define rxSockInfo(fmt, ...) logger.info("RxSockets: " fmt, ##__VA_ARGS__)
#define rxSockDebug(fmt, ...) logger.debug("RxSockets: " fmt, ##__VA_ARGS__)
namespace srsran {
@ -243,63 +244,53 @@ bool connect_to(int fd, const char* dest_addr_str, int dest_port, sockaddr_in* d
* Socket Classes
*******************************************/
socket_handler_t::socket_handler_t(socket_handler_t&& other) noexcept
unique_socket::unique_socket(unique_socket&& other) noexcept : sockfd(other.sockfd), addr(other.addr)
{
sockfd = other.sockfd;
addr = other.addr;
other.sockfd = 0;
other.sockfd = -1;
other.addr = {};
}
socket_handler_t::~socket_handler_t()
unique_socket::~unique_socket()
{
reset();
close();
}
socket_handler_t& socket_handler_t::operator=(socket_handler_t&& other) noexcept
unique_socket& unique_socket::operator=(unique_socket&& other) noexcept
{
if (this == &other) {
return *this;
}
addr = other.addr;
sockfd = other.sockfd;
addr = other.addr;
other.sockfd = -1;
other.addr = {};
other.sockfd = 0;
return *this;
}
void socket_handler_t::close()
void unique_socket::close()
{
if (sockfd >= 0) {
::close(sockfd);
sockfd = -1;
}
}
void socket_handler_t::reset()
{
this->close();
addr = {};
}
}
bool socket_handler_t::bind_addr(const char* bind_addr_str, int port)
bool unique_socket::bind_addr(const char* bind_addr_str, int port)
{
return net_utils::bind_addr(sockfd, bind_addr_str, port, &addr);
}
bool socket_handler_t::connect_to(const char* dest_addr_str, int dest_port, sockaddr_in* dest_sockaddr)
bool unique_socket::connect_to(const char* dest_addr_str, int dest_port, sockaddr_in* dest_sockaddr)
{
return net_utils::connect_to(sockfd, dest_addr_str, dest_port, dest_sockaddr);
}
bool socket_handler_t::open_socket(net_utils::addr_family ip_type,
bool unique_socket::open_socket(net_utils::addr_family ip_type,
net_utils::socket_type socket_type,
net_utils::protocol_type protocol)
{
if (sockfd >= 0) {
if (is_open()) {
srslog::fetch_basic_logger(LOGSERVICE).error("Socket is already open.");
return false;
}
sockfd = net_utils::open_socket(ip_type, socket_type, protocol);
return sockfd >= 0;
return is_open();
}
/***********************************************************************
@ -308,24 +299,24 @@ bool socket_handler_t::open_socket(net_utils::addr_family ip_type,
namespace net_utils {
bool sctp_init_socket(socket_handler_t* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port)
bool sctp_init_socket(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port)
{
if (not socket->open_socket(net_utils::addr_family::ipv4, socktype, net_utils::protocol_type::SCTP)) {
return false;
}
if (not socket->bind_addr(bind_addr_str, port)) {
socket->reset();
socket->close();
return false;
}
return true;
}
bool sctp_init_client(socket_handler_t* socket, net_utils::socket_type socktype, const char* bind_addr_str)
bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str)
{
return sctp_init_socket(socket, socktype, bind_addr_str, 0);
}
bool sctp_init_server(socket_handler_t* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port)
bool sctp_init_server(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port)
{
if (not sctp_init_socket(socket, socktype, bind_addr_str, port)) {
return false;
@ -338,182 +329,25 @@ bool sctp_init_server(socket_handler_t* socket, net_utils::socket_type socktype,
return true;
}
/***************************************************************
* TCP Socket
**************************************************************/
bool tcp_make_server(socket_handler_t* socket, const char* bind_addr_str, int port, int nof_connections)
{
if (not socket->open_socket(addr_family::ipv4, socket_type::stream, protocol_type::TCP)) {
return false;
}
if (not socket->bind_addr(bind_addr_str, port)) {
socket->reset();
return false;
}
// Listen for connections
if (listen(socket->fd(), nof_connections) != 0) {
srslog::fetch_basic_logger(LOGSERVICE).error("Failed to listen to incoming TCP connections");
return false;
}
return true;
}
int tcp_accept(socket_handler_t* socket, sockaddr_in* destaddr)
{
socklen_t clilen = sizeof(destaddr);
int connfd = accept(socket->fd(), (struct sockaddr*)&destaddr, &clilen);
if (connfd < 0) {
srslog::fetch_basic_logger(LOGSERVICE).error("Failed to accept connection");
perror("accept");
return -1;
}
return connfd;
}
int tcp_read(int remotefd, void* buf, size_t nbytes)
{
int n = ::read(remotefd, buf, nbytes);
if (n == 0) {
srslog::fetch_basic_logger(LOGSERVICE).info("TCP connection closed");
close(remotefd);
return 0;
}
if (n == -1) {
srslog::fetch_basic_logger(LOGSERVICE).error("Failed to read from TCP socket.");
perror("TCP read");
}
return n;
}
int tcp_send(int remotefd, const void* buf, size_t nbytes)
{
// Loop until all bytes are sent
char* ptr = (char*)buf;
ssize_t nbytes_remaining = nbytes;
while (nbytes_remaining > 0) {
ssize_t i = ::send(remotefd, ptr, nbytes_remaining, 0);
if (i < 1) {
srslog::fetch_basic_logger(LOGSERVICE).error("Failed to send data to TCP socket");
perror("Error calling send()\n");
return i;
}
ptr += i;
nbytes_remaining -= i;
}
return nbytes - nbytes_remaining;
}
} // namespace net_utils
/***************************************************************
* Rx Multisocket Task Types
**************************************************************/
/**
* Description: Specialization of recv_task for the case the received data is
* in the form of unique_byte_buffer, and a recvfrom(...) call is used
*/
class recvfrom_pdu_task final : public rx_multisocket_handler::recv_task
{
public:
using callback_t = std::function<void(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from)>;
explicit recvfrom_pdu_task(srslog::basic_logger& logger, callback_t func_) : logger(logger), func(std::move(func_)) {}
bool operator()(int fd) override
{
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
ssize_t n_recv = recvfrom(fd, pdu->msg, pdu->get_tailroom(), 0, (struct sockaddr*)&from, &fromlen);
if (n_recv == -1 and errno != EAGAIN) {
logger.error("Error reading from socket: %s", strerror(errno));
return true;
}
if (n_recv == -1 and errno == EAGAIN) {
logger.debug("Socket timeout reached");
return true;
}
pdu->N_bytes = static_cast<uint32_t>(n_recv);
func(std::move(pdu), from);
return true;
}
private:
srslog::basic_logger& logger;
callback_t func;
};
class sctp_recvmsg_pdu_task final : public rx_multisocket_handler::recv_task
{
public:
using callback_t = std::function<
void(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags)>;
explicit sctp_recvmsg_pdu_task(srslog::basic_logger& logger, callback_t func_) :
logger(logger), func(std::move(func_))
{}
bool operator()(int fd) override
{
// inside rx_sockets thread. Read socket
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
sctp_sndrcvinfo sri = {};
int flags = 0;
ssize_t n_recv = sctp_recvmsg(fd, pdu->msg, pdu->get_tailroom(), (struct sockaddr*)&from, &fromlen, &sri, &flags);
if (n_recv == -1 and errno != EAGAIN) {
logger.error("Error reading from SCTP socket: %s", strerror(errno));
return true;
}
if (n_recv == -1 and errno == EAGAIN) {
logger.debug("Socket timeout reached");
return true;
}
bool ret = true;
pdu->N_bytes = static_cast<uint32_t>(n_recv);
// SCTP notifications handled in callback.
func(std::move(pdu), from, sri, flags);
return ret;
}
private:
srslog::basic_logger& logger;
callback_t func;
};
/***************************************************************
* Rx Multisocket Handler
**************************************************************/
rx_multisocket_handler::rx_multisocket_handler(std::string name_, srslog::basic_logger& logger, int thread_prio) :
thread(name_), name(std::move(name_)), logger(logger)
socket_manager::socket_manager() : thread("RXsockets"), socket_manager_itf(srslog::fetch_basic_logger("COMN"))
{
// register control pipe fd
if (pipe(pipefd) == -1) {
rxSockInfo("Failed to open control pipe");
return;
}
srsran_assert(pipe(pipefd) != -1, "Failed to open control pipe");
start(thread_prio);
}
rx_multisocket_handler::~rx_multisocket_handler()
socket_manager::~socket_manager()
{
stop();
}
void rx_multisocket_handler::stop()
void socket_manager::stop()
{
if (running) {
// close thread
@ -538,27 +372,7 @@ void rx_multisocket_handler::stop()
}
}
/**
* Convenience method for read PDUs from socket
*/
bool rx_multisocket_handler::add_socket_pdu_handler(int fd, recvfrom_callback_t pdu_task)
{
std::unique_ptr<srsran::rx_multisocket_handler::recv_task> task;
task.reset(new srsran::recvfrom_pdu_task(logger, std::move(pdu_task)));
return add_socket_handler(fd, std::move(task));
}
/**
* Convenience method for reading PDUs from SCTP socket
*/
bool rx_multisocket_handler::add_socket_sctp_pdu_handler(int fd, sctp_recv_callback_t pdu_task)
{
srsran::rx_multisocket_handler::task_callback_t task;
task.reset(new srsran::sctp_recvmsg_pdu_task(logger, std::move(pdu_task)));
return add_socket_handler(fd, std::move(task));
}
bool rx_multisocket_handler::add_socket_handler(int fd, task_callback_t handler)
bool socket_manager::add_socket_handler(int fd, recv_callback_t handler)
{
std::lock_guard<std::mutex> lock(socket_mutex);
if (fd < 0) {
@ -570,7 +384,7 @@ bool rx_multisocket_handler::add_socket_handler(int fd, task_callback_t handler)
return false;
}
active_sockets.insert(std::pair<const int, task_callback_t>(fd, std::move(handler)));
active_sockets.insert(std::make_pair(fd, std::move(handler)));
// this unlocks the reading thread to add new connections
ctrl_cmd_t msg;
@ -585,18 +399,19 @@ bool rx_multisocket_handler::add_socket_handler(int fd, task_callback_t handler)
return true;
}
bool rx_multisocket_handler::remove_socket(int fd)
bool socket_manager::remove_socket_nonblocking(int fd, bool signal_completion)
{
std::lock_guard<std::mutex> lock(socket_mutex);
auto it = active_sockets.find(fd);
if (it == active_sockets.end()) {
rxSockError("The socket fd=%d to be removed does not exist", fd);
rxSockWarn("The socket fd=%d to be removed does not exist", fd);
return false;
}
ctrl_cmd_t msg;
msg.cmd = ctrl_cmd_t::cmd_id_t::RM_FD;
msg.new_fd = fd;
msg.signal_rm_complete = signal_completion;
if (write(pipefd[1], &msg, sizeof(msg)) != sizeof(msg)) {
rxSockError("while writing to control pipe");
return false;
@ -604,8 +419,23 @@ bool rx_multisocket_handler::remove_socket(int fd)
return true;
}
std::map<int, rx_multisocket_handler::task_callback_t>::iterator
rx_multisocket_handler::remove_socket_unprotected(int fd, fd_set* total_fd_set, int* max_fd)
bool socket_manager::remove_socket(int fd)
{
bool result = remove_socket_nonblocking(fd, true);
// block waiting for socket removal
if (result) {
std::unique_lock<std::mutex> lock(socket_mutex);
while (std::count(rem_fd_tmp_list.begin(), rem_fd_tmp_list.end(), fd) == 0) {
rem_cvar.wait(lock);
}
rem_fd_tmp_list.erase(std::find(rem_fd_tmp_list.begin(), rem_fd_tmp_list.end(), fd));
}
return result;
}
std::map<int, socket_manager::recv_callback_t>::iterator
socket_manager::remove_socket_unprotected(int fd, fd_set* total_fd_set, int* max_fd)
{
if (fd < 0) {
rxSockError("fd to be removed is not valid");
@ -620,7 +450,7 @@ rx_multisocket_handler::remove_socket_unprotected(int fd, fd_set* total_fd_set,
return it;
}
void rx_multisocket_handler::run_thread()
void socket_manager::run_thread()
{
running = true;
fd_set total_fd_set, read_fd_set;
@ -650,12 +480,12 @@ void rx_multisocket_handler::run_thread()
// call read callback for all SCTP/TCP/UDP connections
for (auto handler_it = active_sockets.begin(); handler_it != active_sockets.end();) {
int fd = handler_it->first;
recv_task* callback = handler_it->second.get();
recv_callback_t& callback = handler_it->second;
if (not FD_ISSET(fd, &read_fd_set)) {
++handler_it;
continue;
}
bool socket_valid = callback->operator()(fd);
bool socket_valid = callback(fd);
if (not socket_valid) {
rxSockInfo("The socket fd=%d has been closed by peer", fd);
handler_it = remove_socket_unprotected(fd, &total_fd_set, &max_fd);
@ -686,6 +516,10 @@ void rx_multisocket_handler::run_thread()
break;
case ctrl_cmd_t::cmd_id_t::RM_FD:
remove_socket_unprotected(msg.new_fd, &total_fd_set, &max_fd);
if (msg.signal_rm_complete) {
rem_fd_tmp_list.push_back(msg.new_fd);
rem_cvar.notify_one();
}
rxSockDebug("Socket fd=%d has been successfully removed", msg.new_fd);
break;
default:
@ -695,4 +529,115 @@ void rx_multisocket_handler::run_thread()
}
}
/***************************************************************
* Rx Multisocket Task Types
**************************************************************/
class sctp_recvmsg_pdu_task
{
public:
using callback_t = sctp_recv_callback_t;
explicit sctp_recvmsg_pdu_task(srslog::basic_logger& logger, srsran::task_queue_handle& queue_, callback_t func_) :
logger(logger), queue(queue_), func(std::move(func_))
{}
bool operator()(int fd)
{
// inside rx_sockets thread. Read socket
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
sctp_sndrcvinfo sri = {};
int flags = 0;
ssize_t n_recv = sctp_recvmsg(fd, pdu->msg, pdu->get_tailroom(), (struct sockaddr*)&from, &fromlen, &sri, &flags);
if (n_recv == -1 and errno != EAGAIN) {
logger.error("Error reading from SCTP socket: %s", strerror(errno));
return true;
}
if (n_recv == -1 and errno == EAGAIN) {
logger.debug("Socket timeout reached");
return true;
}
bool ret = true;
pdu->N_bytes = static_cast<uint32_t>(n_recv);
// Defer handling of received packet to provided queue
// SCTP notifications handled in callback.
queue.push(std::bind(
[this, from, sri, flags](srsran::unique_byte_buffer_t& sdu) { func(std::move(sdu), from, sri, flags); },
std::move(pdu)));
return ret;
}
private:
srslog::basic_logger& logger;
srsran::task_queue_handle& queue;
callback_t func;
};
socket_manager_itf::recv_callback_t
make_sctp_sdu_handler(srslog::basic_logger& logger, srsran::task_queue_handle& queue, sctp_recv_callback_t rx_callback)
{
return socket_manager_itf::recv_callback_t(sctp_recvmsg_pdu_task(logger, queue, std::move(rx_callback)));
}
/**
* Description: Functor for the case the received data is
* in the form of unique_byte_buffer, and a recvfrom(...) call is used
*/
class recvfrom_pdu_task
{
public:
using callback_t = recvfrom_callback_t;
explicit recvfrom_pdu_task(srslog::basic_logger& logger, srsran::task_queue_handle& queue_, callback_t func_) :
logger(logger), queue(queue_), func(std::move(func_))
{}
bool operator()(int fd)
{
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Unable to allocate byte buffer");
return true;
}
sockaddr_in from = {};
socklen_t fromlen = sizeof(from);
ssize_t n_recv = recvfrom(fd, pdu->msg, pdu->get_tailroom(), 0, (struct sockaddr*)&from, &fromlen);
if (n_recv == -1 and errno != EAGAIN) {
logger.error("Error reading from socket: %s", strerror(errno));
return true;
}
if (n_recv == -1 and errno == EAGAIN) {
logger.debug("Socket timeout reached");
return true;
}
pdu->N_bytes = static_cast<uint32_t>(n_recv);
// Defer handling of received packet to provided queue
queue.push(
std::bind([this, from](srsran::unique_byte_buffer_t& sdu) { func(std::move(sdu), from); }, std::move(pdu)));
return true;
}
private:
srslog::basic_logger& logger;
srsran::task_queue_handle& queue;
callback_t func;
};
socket_manager_itf::recv_callback_t
make_sdu_handler(srslog::basic_logger& logger, srsran::task_queue_handle& queue, recvfrom_callback_t rx_callback)
{
return socket_manager_itf::recv_callback_t(recvfrom_pdu_task(logger, queue, std::move(rx_callback)));
}
} // namespace srsran

@ -91,7 +91,8 @@ void thread_pool::init_worker(uint32_t id, worker* obj, uint32_t prio, uint32_t
void thread_pool::stop()
{
mutex_queue.lock();
{
std::lock_guard<std::mutex> lock(mutex_queue);
/* Stop any thread waiting for available worker */
running = false;
@ -105,7 +106,7 @@ void thread_pool::stop()
cvar_queue.notify_all();
}
}
mutex_queue.unlock();
}
for (uint32_t i = 0; i < nof_workers; i++) {
debug_thread("stop(): waiting %d\n", i);
@ -145,6 +146,12 @@ void thread_pool::worker::finished()
}
}
bool thread_pool::worker::is_stopped() const
{
std::lock_guard<std::mutex> lock(my_parent->mutex_queue);
return my_parent->status[my_id] == STOP;
}
bool thread_pool::find_finished_worker(uint32_t tti, uint32_t* id)
{
for (uint32_t i = 0; i < nof_workers; i++) {

@ -130,6 +130,11 @@ void mac_rar_subpdu_nr::set_backoff(const uint8_t backoff_indicator_)
backoff_indicator = backoff_indicator_;
}
uint8_t mac_rar_subpdu_nr::get_backoff() const
{
return backoff_indicator;
}
std::array<uint8_t, mac_rar_subpdu_nr::UL_GRANT_NBITS> mac_rar_subpdu_nr::get_ul_grant() const
{
return ul_grant;

@ -23,8 +23,6 @@
namespace srsran {
mac_sch_subpdu_nr::mac_sch_subpdu_nr(mac_sch_pdu_nr* parent_) : parent(parent_) {}
mac_sch_subpdu_nr::nr_lcid_sch_t mac_sch_subpdu_nr::get_type()
{
if (lcid >= 32) {
@ -94,11 +92,11 @@ void mac_sch_subpdu_nr::set_sdu(const uint32_t lcid_, const uint8_t* payload_, c
F_bit = false;
sdu_length = sizeof_ce(lcid, parent->is_ulsch());
if (len_ != static_cast<uint32_t>(sdu_length)) {
srslog::fetch_basic_logger("MAC").warning("Invalid SDU length of UL-SCH SDU (%d != %d)", len_, sdu_length);
logger->warning("Invalid SDU length of UL-SCH SDU (%d != %d)", len_, sdu_length);
}
}
if (sdu_length >= 256) {
if (sdu_length >= MAC_SUBHEADER_LEN_THRESHOLD) {
F_bit = true;
header_length += 1;
}
@ -145,6 +143,9 @@ void mac_sch_subpdu_nr::set_sbsr(const lcg_bsr_t bsr_)
ce_write_buffer.at(0) = ((bsr_.lcg_id & 0x07) << 5) | (bsr_.buffer_size & 0x1f);
}
// Turn a subPDU into a long BSR with variable size
void mac_sch_subpdu_nr::set_lbsr(const std::array<mac_sch_subpdu_nr::lcg_bsr_t, max_num_lcg_lbsr> bsr_) {}
// Section 6.1.2
uint32_t mac_sch_subpdu_nr::write_subpdu(const uint8_t* start_)
{
@ -166,7 +167,7 @@ uint32_t mac_sch_subpdu_nr::write_subpdu(const uint8_t* start_)
} else if (header_length == 1) {
// do nothing
} else {
srslog::fetch_basic_logger("MAC").warning("Error while packing PDU. Unsupported header length (%d)", header_length);
logger->error("Error while packing PDU. Unsupported header length (%d)", header_length);
}
// copy SDU payload
@ -227,6 +228,16 @@ uint8_t mac_sch_subpdu_nr::get_pcmax()
return 0;
}
mac_sch_subpdu_nr::ta_t mac_sch_subpdu_nr::get_ta()
{
ta_t ta = {};
if (lcid == TA_CMD) {
ta.tag_id = (sdu[0] & 0xc0) >> 6;
ta.ta_command = sdu[0] & 0x3f;
}
return ta;
}
mac_sch_subpdu_nr::lcg_bsr_t mac_sch_subpdu_nr::get_sbsr()
{
lcg_bsr_t sbsr = {};
@ -297,7 +308,7 @@ void mac_sch_pdu_nr::unpack(const uint8_t* payload, const uint32_t& len)
while (offset < len) {
mac_sch_subpdu_nr sch_pdu(this);
if (sch_pdu.read_subheader(payload + offset) == SRSRAN_ERROR) {
fprintf(stderr, "Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
logger.error("Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
return;
}
offset += sch_pdu.get_total_length();
@ -310,7 +321,7 @@ void mac_sch_pdu_nr::unpack(const uint8_t* payload, const uint32_t& len)
subpdus.push_back(sch_pdu);
}
if (offset != len) {
fprintf(stderr, "Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
logger.error("Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
}
}
@ -369,7 +380,7 @@ uint32_t mac_sch_pdu_nr::add_sdu(const uint32_t lcid_, const uint8_t* payload_,
{
int header_size = size_header_sdu(lcid_, len_);
if (header_size + len_ > remaining_len) {
printf("Header and SDU exceed space in PDU (%d > %d).\n", header_size + len_, remaining_len);
logger.error("Header and SDU exceed space in PDU (%d + %d > %d)", header_size, len_, remaining_len);
return SRSRAN_ERROR;
}
@ -399,6 +410,14 @@ uint32_t mac_sch_pdu_nr::add_sbsr_ce(const mac_sch_subpdu_nr::lcg_bsr_t bsr_)
return add_sudpdu(ce);
}
uint32_t
mac_sch_pdu_nr::add_lbsr_ce(const std::array<mac_sch_subpdu_nr::lcg_bsr_t, mac_sch_subpdu_nr::max_num_lcg_lbsr> bsr_)
{
mac_sch_subpdu_nr ce(this);
ce.set_lbsr(bsr_);
return add_sudpdu(ce);
}
uint32_t mac_sch_pdu_nr::add_sudpdu(mac_sch_subpdu_nr& subpdu)
{
uint32_t subpdu_len = subpdu.get_total_length();

@ -38,6 +38,7 @@
/// @brief Enables interpolation at CCE frequency bandwidth to avoid interference with adjacent PDCCH DMRS
#define DMRS_PDCCH_INTERPOLATE_GROUP 1
#define DMRS_PDCCH_SMOOTH_FILTER 0
static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uint32_t n_id)
{
@ -370,6 +371,7 @@ int srsran_dmrs_pdcch_estimate(srsran_dmrs_pdcch_estimator_t* q,
uint32_t group_size = NOF_PILOTS_X_FREQ_RES / q->coreset.duration;
for (uint32_t l = 0; l < q->coreset.duration; l++) {
for (uint32_t j = 0; j < group_count; j++) {
#if DMRS_PDCCH_SMOOTH_FILTER
cf_t tmp[NOF_PILOTS_X_FREQ_RES];
// Smoothing filter group
@ -377,13 +379,20 @@ int srsran_dmrs_pdcch_estimate(srsran_dmrs_pdcch_estimator_t* q,
srsran_interp_linear_offset(
&q->interpolator, tmp, &q->ce[SRSRAN_NRE * q->coreset_bw * l + j * group_size * 4], 1, 3);
#else // DMRS_PDCCH_SMOOTH_FILTER
srsran_interp_linear_offset(&q->interpolator,
&q->lse[l][j * group_size],
&q->ce[SRSRAN_NRE * q->coreset_bw * l + j * group_size * 4],
1,
3);
#endif // DMRS_PDCCH_SMOOTH_FILTER
}
}
#else
#else // DMRS_PDCCH_INTERPOLATE_GROUP
for (uint32_t l = 0; l < q->coreset.duration; l++) {
srsran_interp_linear_offset(&q->interpolator, q->lse[l], &q->ce[SRSRAN_NRE * q->coreset_bw * l], 1, 3);
}
#endif
#endif // DMRS_PDCCH_INTERPOLATE_GROUP
return SRSRAN_SUCCESS;
}

@ -46,6 +46,36 @@ const char* srsran_rnti_type_str(srsran_rnti_type_t rnti_type)
return "unknown";
}
const char* srsran_dci_format_nr_string(srsran_dci_format_nr_t format)
{
switch (format) {
case srsran_dci_format_nr_0_0:
return "0_0";
case srsran_dci_format_nr_0_1:
return "0_1";
case srsran_dci_format_nr_1_0:
return "1_0";
case srsran_dci_format_nr_1_1:
return "1_1";
case srsran_dci_format_nr_2_0:
return "2_0";
case srsran_dci_format_nr_2_1:
return "2_1";
case srsran_dci_format_nr_2_2:
return "2_2";
case srsran_dci_format_nr_2_3:
return "2_3";
case srsran_dci_format_nr_rar:
return "RAR";
case srsran_dci_format_nr_cg:
return "CG";
default:
case SRSRAN_DCI_FORMAT_NR_COUNT:
break;
}
return "unknown";
}
uint32_t srsran_coreset_get_bw(const srsran_coreset_t* coreset)
{
uint32_t prb_count = 0;

@ -144,15 +144,21 @@ int srsran_enb_dl_nr_set_carrier(srsran_enb_dl_nr_t* q, const srsran_carrier_nr_
return SRSRAN_SUCCESS;
}
int srsran_enb_dl_nr_set_coreset(srsran_enb_dl_nr_t* q, const srsran_coreset_t* coreset)
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)
{
if (q == NULL || coreset == NULL) {
if (q == NULL || cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
q->coreset = *coreset;
q->pdcch_cfg = *cfg;
if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, &q->coreset) < SRSRAN_SUCCESS) {
if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, &q->pdcch_cfg.coreset[0]) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_dci_nr_set_cfg(&q->dci, dci_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
@ -191,15 +197,27 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q,
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (dci_dl->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET ||
!q->pdcch_cfg.coreset_present[dci_dl->ctx.coreset_id]) {
ERROR("Invalid CORESET ID %d", dci_dl->ctx.coreset_id);
return SRSRAN_ERROR;
}
srsran_coreset_t* coreset = &q->pdcch_cfg.coreset[dci_dl->ctx.coreset_id];
if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, coreset) < SRSRAN_SUCCESS) {
ERROR("Error setting PDCCH carrier/CORESET");
return SRSRAN_ERROR;
}
// Put DMRS
if (srsran_dmrs_pdcch_put(&q->carrier, &q->coreset, slot_cfg, &dci_dl->location, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
if (srsran_dmrs_pdcch_put(&q->carrier, coreset, slot_cfg, &dci_dl->ctx.location, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
ERROR("Error putting PDCCH DMRS");
return SRSRAN_ERROR;
}
// Pack DCI
srsran_dci_msg_nr_t dci_msg = {};
if (srsran_dci_nr_pack(&q->carrier, &q->coreset, dci_dl, &dci_msg) < SRSRAN_SUCCESS) {
if (srsran_dci_nr_dl_pack(&q->dci, dci_dl, &dci_msg) < SRSRAN_SUCCESS) {
ERROR("Error packing DL DCI");
return SRSRAN_ERROR;
}
@ -210,7 +228,7 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q,
return SRSRAN_ERROR;
}
INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->location.L, dci_dl->location.ncce);
INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce);
return SRSRAN_SUCCESS;
}

@ -137,93 +137,58 @@ void* create_ldpc_dec_c_avx2long(uint8_t bgN, uint8_t bgM, uint16_t ls, float sc
uint8_t bgK = bgN - bgM;
uint16_t hrr = bgK + 4;
if ((vp = srsran_vec_malloc(sizeof(struct ldpc_regs_c_avx2long))) == NULL) {
if ((vp = SRSRAN_MEM_ALLOC(struct ldpc_regs_c_avx2long, 1)) == NULL) {
return NULL;
}
SRSRAN_MEM_ZERO(vp, struct ldpc_regs_c_avx2long, 1);
// compute number of subnodes
int left_out = ls % SRSRAN_AVX2_B_SIZE;
int n_subnodes = ls / SRSRAN_AVX2_B_SIZE + (left_out > 0);
if ((vp->soft_bits = srsran_vec_malloc(bgN * n_subnodes * sizeof(bg_node_t))) == NULL) {
free(vp);
if ((vp->soft_bits = SRSRAN_MEM_ALLOC(bg_node_t, bgN * n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->check_to_var = srsran_vec_malloc((hrr + 1) * bgM * n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->soft_bits);
free(vp);
if ((vp->check_to_var = SRSRAN_MEM_ALLOC(__m256i, (hrr + 1) * bgM * n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->var_to_check_to_free = srsran_vec_malloc(((hrr + 1) * n_subnodes + 2) * sizeof(__m256i))) == NULL) {
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->var_to_check_to_free = SRSRAN_MEM_ALLOC(__m256i, (hrr + 1) * n_subnodes + 2)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
vp->var_to_check = &vp->var_to_check_to_free[1];
if ((vp->minp_v2c_epi8 = srsran_vec_malloc(n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->minp_v2c_epi8 = SRSRAN_MEM_ALLOC(__m256i, n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->mins_v2c_epi8 = srsran_vec_malloc(n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->minp_v2c_epi8);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->mins_v2c_epi8 = SRSRAN_MEM_ALLOC(__m256i, n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->prod_v2c_epi8 = srsran_vec_malloc(n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->mins_v2c_epi8);
free(vp->minp_v2c_epi8);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->prod_v2c_epi8 = SRSRAN_MEM_ALLOC(__m256i, n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->min_ix_epi8 = srsran_vec_malloc(n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->prod_v2c_epi8);
free(vp->mins_v2c_epi8);
free(vp->minp_v2c_epi8);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->min_ix_epi8 = SRSRAN_MEM_ALLOC(__m256i, n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->rotated_v2c = srsran_vec_malloc((hrr + 1) * n_subnodes * sizeof(__m256i))) == NULL) {
free(vp->min_ix_epi8);
free(vp->prod_v2c_epi8);
free(vp->mins_v2c_epi8);
free(vp->minp_v2c_epi8);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->rotated_v2c = SRSRAN_MEM_ALLOC(__m256i, (hrr + 1) * n_subnodes)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
if ((vp->this_c2v_epi8_to_free = srsran_vec_malloc((n_subnodes + 2) * sizeof(__m256i))) == NULL) {
free(vp->rotated_v2c);
free(vp->min_ix_epi8);
free(vp->prod_v2c_epi8);
free(vp->mins_v2c_epi8);
free(vp->minp_v2c_epi8);
free(vp->var_to_check_to_free);
free(vp->check_to_var);
free(vp->soft_bits);
free(vp);
if ((vp->this_c2v_epi8_to_free = SRSRAN_MEM_ALLOC(__m256i, n_subnodes + 2)) == NULL) {
delete_ldpc_dec_c_avx2long(vp);
return NULL;
}
vp->this_c2v_epi8 =
@ -246,18 +211,37 @@ void delete_ldpc_dec_c_avx2long(void* p)
{
struct ldpc_regs_c_avx2long* vp = p;
if (vp != NULL) {
if (vp == NULL) {
return;
}
if (vp->this_c2v_epi8_to_free) {
free(vp->this_c2v_epi8_to_free);
}
if (vp->rotated_v2c != NULL) {
free(vp->rotated_v2c);
}
if (vp->min_ix_epi8 != NULL) {
free(vp->min_ix_epi8);
}
if (vp->prod_v2c_epi8 != NULL) {
free(vp->prod_v2c_epi8);
}
if (vp->mins_v2c_epi8 != NULL) {
free(vp->mins_v2c_epi8);
}
if (vp->minp_v2c_epi8 != NULL) {
free(vp->minp_v2c_epi8);
}
if (vp->var_to_check_to_free != NULL) {
free(vp->var_to_check_to_free);
}
if (vp->check_to_var != NULL) {
free(vp->check_to_var);
}
if (vp->soft_bits != NULL) {
free(vp->soft_bits);
free(vp);
}
free(vp);
}
int init_ldpc_dec_c_avx2long(void* p, const int8_t* llrs, uint16_t ls)
@ -281,11 +265,14 @@ int init_ldpc_dec_c_avx2long(void* p, const int8_t* llrs, uint16_t ls)
vp->soft_bits[i * vp->n_subnodes + j].c[k] = llrs[(i - 2) * ls + j * SRSRAN_AVX2_B_SIZE + k];
}
}
bzero(&(vp->soft_bits[i * vp->n_subnodes + j - 1].c[k]), (SRSRAN_AVX2_B_SIZE - k) * sizeof(int8_t));
srsran_vec_i8_zero(&(vp->soft_bits[i * vp->n_subnodes + j - 1].c[k]), SRSRAN_AVX2_B_SIZE - k);
}
bzero(vp->check_to_var, (vp->hrr + 1) * vp->bgM * vp->n_subnodes * sizeof(__m256i));
bzero(vp->var_to_check, (vp->hrr + 1) * vp->n_subnodes * sizeof(__m256i));
SRSRAN_MEM_ZERO(vp->check_to_var, __m256i, (vp->hrr + 1) * vp->bgM * vp->n_subnodes);
SRSRAN_MEM_ZERO(vp->var_to_check, __m256i, (vp->hrr + 1) * vp->n_subnodes);
SRSRAN_MEM_ZERO(vp->this_c2v_epi8_to_free, __m256i, vp->n_subnodes + 2);
SRSRAN_MEM_ZERO(vp->min_ix_epi8, __m256i, vp->n_subnodes);
SRSRAN_MEM_ZERO(vp->var_to_check_to_free, __m256i, (vp->hrr + 1) * vp->n_subnodes + 2);
return 0;
}

@ -1037,12 +1037,7 @@ int srsran_ldpc_decoder_decode_s(srsran_ldpc_decoder_t* q,
return q->decode_s(q, llrs, message, cdwd_rm_length);
}
int srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q, const int8_t* llrs, uint8_t* message)
{
return q->decode_c(q, llrs, message, q->liftN - 2 * q->ls);
}
int srsran_ldpc_decoder_decode_rm_c(srsran_ldpc_decoder_t* q,
int srsran_ldpc_decoder_decode_c(srsran_ldpc_decoder_t* q,
const int8_t* llrs,
uint8_t* message,
uint32_t cdwd_rm_length)

@ -695,5 +695,6 @@ int srsran_ldpc_rm_rx_c(srsran_ldpc_rm_t* q,
bit_selection_rm_rx_c(tmp_rm_symbol, q->E, output, indices, ini_exclude, end_exclude, q->k0, q->Ncb);
}
return 0;
// Return the number of useful LLR
return (int)SRSRAN_MIN(q->k0 + q->E, q->Ncb);
}

@ -431,8 +431,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
&decoder_c, symbols_c + j * finalN, messages_sim_c + j * finalK, n_useful_symbols);
srsran_ldpc_decoder_decode_c(&decoder_c, symbols_c + j * finalN, messages_sim_c + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
@ -453,7 +452,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_c_flood, symbols_c + j * finalN, messages_sim_c_flood + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);
@ -476,7 +475,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx, symbols_c + j * finalN, messages_sim_avx + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);
@ -498,7 +497,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx_flood, symbols_c + j * finalN, messages_sim_avx_flood + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);
@ -522,7 +521,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx512, symbols_c + j * finalN, messages_sim_avx512 + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);
@ -543,7 +542,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx512_flood, symbols_c + j * finalN, messages_sim_avx512_flood + j * finalK, n_useful_symbols);
}
gettimeofday(&t[2], NULL);

@ -216,7 +216,7 @@ int main(int argc, char** argv)
printf(" codeword %d\n", j);
gettimeofday(&t[1], NULL);
for (l = 0; l < nof_reps; l++) {
srsran_ldpc_decoder_decode_rm_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
srsran_ldpc_decoder_decode_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
}
gettimeofday(&t[2], NULL);

@ -215,7 +215,7 @@ int main(int argc, char** argv)
printf(" codeword %d\n", j);
gettimeofday(&t[1], NULL);
for (l = 0; l < nof_reps; l++) {
srsran_ldpc_decoder_decode_rm_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
srsran_ldpc_decoder_decode_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
}
gettimeofday(&t[2], NULL);

@ -206,7 +206,7 @@ int main(int argc, char** argv)
gettimeofday(&t[1], NULL);
for (j = 0; j < NOF_MESSAGES; j++) {
printf(" codeword %d\n", j);
srsran_ldpc_decoder_decode_rm_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
srsran_ldpc_decoder_decode_c(&decoder, symbols + j * finalN, messages_sim + j * finalK, finalN);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);

@ -555,7 +555,7 @@ int main(int argc, char** argv)
lift_size,
rv,
mod_type,
Nref)) {
Nref) < 0) {
exit(-1);
}
}
@ -563,7 +563,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_c, symbols_c + j * finalN, messages_sim_c + j * finalK, n_useful_symbols_dec);
}
gettimeofday(&t[2], NULL);
@ -585,7 +585,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_c_flood, symbols_c + j * finalN, messages_sim_c_flood + j * finalK, n_useful_symbols_dec);
}
gettimeofday(&t[2], NULL);
@ -608,7 +608,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx, symbols_c + j * finalN, messages_sim_avx + j * finalK, n_useful_symbols_dec);
}
gettimeofday(&t[2], NULL);
@ -630,7 +630,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx_flood, symbols_c + j * finalN, messages_sim_avx_flood + j * finalK, n_useful_symbols_dec);
}
gettimeofday(&t[2], NULL);
@ -654,8 +654,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
&decoder_avx512, symbols_c + j * finalN, messages_sim_avx512 + j * finalK, finalN);
srsran_ldpc_decoder_decode_c(&decoder_avx512, symbols_c + j * finalN, messages_sim_avx512 + j * finalK, finalN);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
@ -676,7 +675,7 @@ int main(int argc, char** argv)
// Recover messages
gettimeofday(&t[1], NULL);
for (j = 0; j < batch_size; j++) {
srsran_ldpc_decoder_decode_rm_c(
srsran_ldpc_decoder_decode_c(
&decoder_avx512_flood, symbols_c + j * finalN, messages_sim_avx512_flood + j * finalK, finalN);
}
gettimeofday(&t[2], NULL);

@ -265,7 +265,8 @@ int main(int argc, char** argv)
exit(-1);
}
if (srsran_ldpc_rm_rx_c(
&rm_rx_c, rm_symbols_c + r * E, unrm_symbols_c + r * N, E, F, base_graph, lift_size, rv, mod_type, Nref)) {
&rm_rx_c, rm_symbols_c + r * E, unrm_symbols_c + r * N, E, F, base_graph, lift_size, rv, mod_type, Nref) <
0) {
exit(-1);
}
@ -278,7 +279,6 @@ int main(int argc, char** argv)
((unrm_symbols[i + r * N] < 0) && (codewords[i + r * N]))) {
// any of these cases are ok
} else {
error = -1;
break;
}

@ -99,7 +99,7 @@ srsran_tdec_8bit_impl_t avx8_win_impl = {tdec_winavx8_init,
#ifdef HAVE_NEON
#define WINIMP_IS_NEON16
#include "srsran/phy/fec/turbodecoder_win.h"
#include "srsran/phy/fec/turbo/turbodecoder_win.h"
#undef WINIMP_IS_NEON16
srsran_tdec_16bit_impl_t arm16_win_impl = {tdec_winarm16_init,

@ -29,7 +29,7 @@
/// Implements SNRI to CQI conversion
uint32_t csi_snri_db_to_cqi(srsran_csi_cqi_table_t table, float snri_db)
{
return 6;
return 15;
}
// Implements CSI report triggers

File diff suppressed because it is too large Load Diff

@ -333,11 +333,11 @@ static uint32_t pdcch_nr_cp(const srsran_pdcch_nr_t* q,
static uint32_t pdcch_nr_c_init(const srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_msg)
{
uint32_t n_id = (dci_msg->search_space == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
uint32_t n_id = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? q->coreset.dmrs_scrambling_id
: q->carrier.id;
uint32_t n_rnti = (dci_msg->search_space == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? dci_msg->rnti
uint32_t n_rnti = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? dci_msg->ctx.rnti
: 0U;
return ((n_rnti << 16U) + n_id) & 0x7fffffffU;
}
@ -355,7 +355,7 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_
// Calculate...
q->K = dci_msg->nof_bits + 24U; // Payload size including CRC
q->M = (1U << dci_msg->location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE
q->M = (1U << dci_msg->ctx.location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE
q->E = q->M * 2; // Number of Rate-Matched bits
uint32_t cinit = pdcch_nr_c_init(q, dci_msg); // Pseudo-random sequence initiation
@ -380,7 +380,7 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_
// Unpack RNTI
uint8_t unpacked_rnti[16] = {};
uint8_t* ptr = unpacked_rnti;
srsran_bit_unpack(dci_msg->rnti, &ptr, 16);
srsran_bit_unpack(dci_msg->ctx.rnti, &ptr, 16);
// Scramble CRC with RNTI
srsran_vec_xor_bbb(unpacked_rnti, &c[q->K - 16], &c[q->K - 16], 16);
@ -421,7 +421,7 @@ int srsran_pdcch_nr_encode(srsran_pdcch_nr_t* q, const srsran_dci_msg_nr_t* dci_
srsran_mod_modulate(&q->modem_table, q->f, q->symbols, q->E);
// Put symbols in grid
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true);
uint32_t m = pdcch_nr_cp(q, &dci_msg->ctx.location, slot_symbols, q->symbols, true);
if (q->M != m) {
ERROR("Unmatch number of RE (%d != %d)", m, q->M);
return SRSRAN_ERROR;
@ -459,7 +459,7 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q,
// Calculate...
q->K = dci_msg->nof_bits + 24U; // Payload size including CRC
q->M = (1U << dci_msg->location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE
q->M = (1U << dci_msg->ctx.location.L) * (SRSRAN_NRE - 3U) * 6U; // Number of RE
q->E = q->M * 2; // Number of Rate-Matched bits
// Check number of estimates is correct
@ -475,7 +475,7 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q,
PDCCH_INFO_RX("K=%d; E=%d; M=%d; n=%d;", q->K, q->E, q->M, q->code.n);
// Get symbols from grid
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false);
uint32_t m = pdcch_nr_cp(q, &dci_msg->ctx.location, slot_symbols, q->symbols, false);
if (q->M != m) {
ERROR("Unmatch number of RE (%d != %d)", m, q->M);
return SRSRAN_ERROR;
@ -555,7 +555,7 @@ int srsran_pdcch_nr_decode(srsran_pdcch_nr_t* q,
// Unpack RNTI
uint8_t unpacked_rnti[16] = {};
uint8_t* ptr = unpacked_rnti;
srsran_bit_unpack(dci_msg->rnti, &ptr, 16);
srsran_bit_unpack(dci_msg->ctx.rnti, &ptr, 16);
// De-Scramble CRC with RNTI
srsran_vec_xor_bbb(unpacked_rnti, &c[q->K - 16], &c[q->K - 16], 16);

@ -741,7 +741,7 @@ static uint32_t pucch_nr_resource_info(const srsran_pucch_nr_resource_t* r, char
len = srsran_print_check(str,
str_len,
len,
"f=%d, prb=%d:%d, symb=%d:%d",
"f=%d prb=%d:%d symb=%d:%d ",
(int)r->format,
r->starting_prb,
nof_prb,
@ -749,19 +749,19 @@ static uint32_t pucch_nr_resource_info(const srsran_pucch_nr_resource_t* r, char
r->nof_symbols);
if (r->intra_slot_hopping) {
len = srsran_print_check(str, str_len, len, ", hop=%d", r->second_hop_prb);
len = srsran_print_check(str, str_len, len, "hop=%d ", r->second_hop_prb);
}
if (r->format == SRSRAN_PUCCH_NR_FORMAT_0 || r->format == SRSRAN_PUCCH_NR_FORMAT_1) {
len = srsran_print_check(str, str_len, len, ", cs=%d", r->initial_cyclic_shift);
len = srsran_print_check(str, str_len, len, "cs=%d ", r->initial_cyclic_shift);
}
if (r->format == SRSRAN_PUCCH_NR_FORMAT_1) {
len = srsran_print_check(str, str_len, len, ", occ=%d", r->time_domain_occ);
len = srsran_print_check(str, str_len, len, "occ=%d ", r->time_domain_occ);
}
if (r->format == SRSRAN_PUCCH_NR_FORMAT_4) {
len = srsran_print_check(str, str_len, len, ", occ=%d:%d", r->occ_index, r->occ_lenth);
len = srsran_print_check(str, str_len, len, "occ=%d:%d ", r->occ_index, r->occ_lenth);
}
return len;
@ -776,7 +776,7 @@ uint32_t srsran_pucch_nr_tx_info(const srsran_pucch_nr_resource_t* resource,
len += pucch_nr_resource_info(resource, &str[len], str_len - len);
len = srsran_print_check(str, str_len, len, ", ");
len = srsran_print_check(str, str_len, len, "rnti=0x%x ", uci_data->cfg.pucch.rnti);
len += srsran_uci_nr_info(uci_data, &str[len], str_len - len);

@ -62,6 +62,8 @@ int pusch_nr_init_common(srsran_pusch_nr_t* q, const srsran_pusch_nr_args_t* arg
return SRSRAN_ERROR;
}
q->meas_time_en = args->measure_time;
return SRSRAN_SUCCESS;
}
@ -106,8 +108,6 @@ int srsran_pusch_nr_init_gnb(srsran_pusch_nr_t* q, const srsran_pusch_nr_args_t*
}
}
q->meas_time_en = args->measure_time;
return SRSRAN_SUCCESS;
}

@ -71,7 +71,7 @@ int srsran_ra_dl_nr_time_default_A(uint32_t m, srsran_dmrs_sch_typeA_pos_t dmrs_
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) {
if (m >= SRSRAN_MAX_NOF_TIME_RA) {
ERROR("m (%d) is out-of-range", m);
return SRSRAN_ERROR_INVALID_INPUTS;
}
@ -98,10 +98,10 @@ int srsran_ra_dl_nr_time_default_A(uint32_t m, srsran_dmrs_sch_typeA_pos_t dmrs_
srsran_sch_mapping_type_B};
grant->mapping = pdsch_mapping_lut[m];
static uint32_t S_pos2[SRSRAN_MAX_NOF_DL_ALLOCATION] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos2[SRSRAN_MAX_NOF_DL_ALLOCATION] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
static uint32_t S_pos3[SRSRAN_MAX_NOF_DL_ALLOCATION] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos3[SRSRAN_MAX_NOF_DL_ALLOCATION] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
static uint32_t S_pos2[SRSRAN_MAX_NOF_TIME_RA] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos2[SRSRAN_MAX_NOF_TIME_RA] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
static uint32_t S_pos3[SRSRAN_MAX_NOF_TIME_RA] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos3[SRSRAN_MAX_NOF_TIME_RA] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
// Select start symbol (S) and length (L)
switch (dmrs_typeA_pos) {
@ -141,7 +141,7 @@ int srsran_ra_dl_nr_time(const srsran_sch_hl_cfg_nr_t* cfg,
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) {
if (m >= SRSRAN_MAX_NOF_TIME_RA) {
ERROR("m (%d) is out-of-range", m);
return SRSRAN_ERROR_INVALID_INPUTS;
}
@ -186,7 +186,7 @@ int srsran_ra_dl_nr_time(const srsran_sch_hl_cfg_nr_t* cfg,
srsran_ra_dl_nr_time_default_A(m, cfg->typeA_pos, grant);
}
} else {
ERROR("Unhandled case");
ERROR("Unhandled case %s, ss_type=%d", srsran_rnti_type_str(rnti_type), ss_type);
}
// Validate S and L parameters
@ -273,7 +273,7 @@ int srsran_ra_dl_nr_freq(const srsran_carrier_nr_t* carrier,
}
// RA scheme
if (dci_dl->format == srsran_dci_format_nr_1_0) {
if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) {
// when the scheduling grant is received with DCI format 1_0 , then downlink resource allocation type 1 is used.
return ra_helper_freq_type1(carrier->nof_prb, dci_dl->freq_domain_assigment, grant);
}

@ -662,9 +662,9 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
{
// 5.2.1.1 Resource allocation in time domain
if (srsran_ra_dl_nr_time(pdsch_hl_cfg,
dci_dl->rnti_type,
dci_dl->search_space,
dci_dl->coreset_id,
dci_dl->ctx.rnti_type,
dci_dl->ctx.ss_type,
dci_dl->ctx.coreset_id,
dci_dl->time_domain_assigment,
pdsch_grant) < SRSRAN_SUCCESS) {
ERROR("Error computing time domain resource allocation");
@ -681,9 +681,9 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
// ...
pdsch_grant->nof_layers = 1;
pdsch_grant->dci_format = dci_dl->format;
pdsch_grant->rnti = dci_dl->rnti;
pdsch_grant->rnti_type = dci_dl->rnti_type;
pdsch_grant->dci_format = dci_dl->ctx.format;
pdsch_grant->rnti = dci_dl->ctx.rnti;
pdsch_grant->rnti_type = dci_dl->ctx.rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv;
// 5.1.4 PDSCH resource mapping
@ -714,7 +714,8 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, srsran_sch_grant_nr_t* pu
? pusch_hl_cfg->dmrs_typeA.present
: pusch_hl_cfg->dmrs_typeB.present;
if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || !dedicated_dmrs_present) {
if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || pusch_grant->dci_format == srsran_dci_format_nr_rar ||
!dedicated_dmrs_present) {
if (pusch_grant->mapping == srsran_sch_mapping_type_A) {
// Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig
cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2;
@ -743,13 +744,13 @@ ra_ul_dmrs(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, srsran_sch_grant_nr_t* pu
}
// Set number of DMRS CDM groups without data
if (pusch_grant->dci_format == srsran_dci_format_nr_0_0) {
if (pusch_grant->dci_format == srsran_dci_format_nr_0_0 || pusch_grant->dci_format == srsran_dci_format_nr_rar) {
if (srsran_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(cfg, pusch_grant) < SRSRAN_SUCCESS) {
ERROR("Error loading number of DMRS CDM groups");
return SRSRAN_ERROR;
}
} else {
ERROR("Invalid case");
ERROR("DCI format not implemented %s", srsran_dci_format_nr_string(pusch_grant->dci_format));
return SRSRAN_ERROR;
}
@ -770,9 +771,9 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
{
// 5.2.1.1 Resource allocation in time domain
if (srsran_ra_ul_nr_time(pusch_hl_cfg,
dci_ul->rnti_type,
dci_ul->search_space,
dci_ul->coreset_id,
dci_ul->ctx.rnti_type,
dci_ul->ctx.ss_type,
dci_ul->ctx.coreset_id,
dci_ul->time_domain_assigment,
pusch_grant) < SRSRAN_SUCCESS) {
ERROR("Error computing time domain resource allocation");
@ -789,9 +790,9 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
// ...
pusch_grant->nof_layers = 1;
pusch_grant->dci_format = dci_ul->format;
pusch_grant->rnti = dci_ul->rnti;
pusch_grant->rnti_type = dci_ul->rnti_type;
pusch_grant->dci_format = dci_ul->ctx.format;
pusch_grant->rnti = dci_ul->ctx.rnti;
pusch_grant->rnti_type = dci_ul->ctx.rnti_type;
// 5.1.6.2 DM-RS reception procedure
if (ra_ul_dmrs(pusch_hl_cfg, pusch_grant, pusch_cfg) < SRSRAN_SUCCESS) {

@ -141,7 +141,7 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg,
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (m >= SRSRAN_MAX_NOF_DL_ALLOCATION) {
if (m >= SRSRAN_MAX_NOF_TIME_RA) {
ERROR("m (%d) is out-of-range", m);
return SRSRAN_ERROR_INVALID_INPUTS;
}
@ -151,12 +151,12 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg,
// Row 1
if (cfg->nof_common_time_ra == 0) {
srsran_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant);
} else if (m < SRSRAN_MAX_NOF_DL_ALLOCATION && m < cfg->nof_common_time_ra) {
} else if (m < SRSRAN_MAX_NOF_TIME_RA && m < cfg->nof_common_time_ra) {
ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant);
} else {
ERROR("Time domain resource selection (m=%d) exceeds the maximum value (%d)",
m,
SRSRAN_MIN(cfg->nof_common_time_ra, SRSRAN_MAX_NOF_DL_ALLOCATION));
SRSRAN_MIN(cfg->nof_common_time_ra, SRSRAN_MAX_NOF_TIME_RA));
}
} else if ((rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_mcs_c ||
rnti_type == srsran_rnti_type_tc || rnti_type == srsran_rnti_type_cs) &&
@ -164,7 +164,7 @@ int srsran_ra_ul_nr_time(const srsran_sch_hl_cfg_nr_t* cfg,
// Row 2
if (cfg->nof_common_time_ra == 0) {
srsran_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant);
} else if (m < SRSRAN_MAX_NOF_DL_ALLOCATION) {
} else if (m < SRSRAN_MAX_NOF_TIME_RA) {
ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant);
}
} else if ((rnti_type == srsran_rnti_type_c || rnti_type == srsran_rnti_type_mcs_c ||
@ -383,12 +383,12 @@ int srsran_ra_ul_nr_freq(const srsran_carrier_nr_t* carrier,
}
// RA scheme
if (dci_ul->format == srsran_dci_format_nr_0_0) {
if (dci_ul->ctx.format == srsran_dci_format_nr_0_0 || dci_ul->ctx.format == srsran_dci_format_nr_rar) {
// when the scheduling grant is received with DCI format 1_0 , then downlink resource allocation type 1 is used.
return ra_helper_freq_type1(carrier->nof_prb, dci_ul->freq_domain_assigment, grant);
}
ERROR("Only DCI Format 0_0 is supported");
ERROR("Unhandled DCI Format %s", srsran_dci_format_nr_string(dci_ul->ctx.format));
return SRSRAN_ERROR;
}

@ -590,10 +590,15 @@ int sch_nr_decode(srsran_sch_nr_t* q,
tb->rv,
cfg.Qm,
cfg.Nref);
int n_llr =
srsran_ldpc_rm_rx_c(&q->rx_rm, input_ptr, rm_buffer, E, cfg.F, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref);
if (n_llr < SRSRAN_SUCCESS) {
ERROR("Error in LDPC rate mateching");
return SRSRAN_ERROR;
}
// Decode
srsran_ldpc_decoder_decode_c(decoder, rm_buffer, q->temp_cb);
srsran_ldpc_decoder_decode_c(decoder, rm_buffer, q->temp_cb, n_llr);
// Compute CB CRC
uint32_t cb_len = cfg.Kp - cfg.L_cb;
@ -652,7 +657,7 @@ int sch_nr_decode(srsran_sch_nr_t* q,
// Check if TB is all zeros
bool all_zeros = true;
for (uint32_t i = 0; i < tb->tbs && all_zeros; i++) {
for (uint32_t i = 0; i < tb->tbs / 8 && all_zeros; i++) {
all_zeros = (data[i] == 0);
}

@ -628,13 +628,24 @@ endif(RF_FOUND)
# NR
########################################################################
add_executable(dci_nr_test dci_nr_test.c)
target_link_libraries(dci_nr_test srsran_phy)
add_nr_test(dci_nr_test dci_nr_test)
add_executable(pucch_nr_test pucch_nr_test.c)
target_link_libraries(pucch_nr_test srsran_phy)
add_nr_test(pucch_nr_test pucch_nr_test)
add_executable(sch_nr_test sch_nr_test.c)
target_link_libraries(sch_nr_test srsran_phy)
add_nr_test(sch_nr_test sch_nr_test -m 0 -p 1)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 1 -r 0)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 1 -r 1)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 10 -r 0)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 10 -r 1)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 20 -r 0)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 20 -r 1)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 52 -r 0)
add_nr_test(sch_nr_test sch_nr_test -P 52 -p 52 -r 1)
add_executable(pdsch_nr_test pdsch_nr_test.c)
target_link_libraries(pdsch_nr_test srsran_phy)

@ -0,0 +1,53 @@
/**
*
* \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/test_common.h"
#include "srsran/phy/phch/dci_nr.h"
static int test_52prb()
{
// Default configuration with all options disabled
srsran_dci_cfg_nr_t cfg = {};
// Set bandwidths
cfg.coreset0_bw = 0;
cfg.bwp_dl_initial_bw = 52;
cfg.bwp_dl_active_bw = 52;
cfg.bwp_ul_initial_bw = 52;
cfg.bwp_ul_active_bw = 52;
// Enable all monitoring
cfg.monitor_common_0_0 = true;
cfg.monitor_0_0_and_1_0 = true;
cfg.monitor_0_1_and_1_1 = true;
// Configure DCI
srsran_dci_nr_t dci = {};
TESTASSERT(srsran_dci_nr_set_cfg(&dci, &cfg) == SRSRAN_SUCCESS);
// Check DCI sizes
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_common_3, srsran_dci_format_nr_0_0) == 39);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_common_3, srsran_dci_format_nr_1_0) == 39);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_0) == 39);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_0) == 39);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_1) == 28);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_1) == 26);
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv)
{
TESTASSERT(test_52prb() == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;
}

@ -52,8 +52,8 @@ static int test(srsran_pdcch_nr_t* tx,
// Encode PDCCH
TESTASSERT(srsran_pdcch_nr_encode(tx, dci_msg_tx, grid) == SRSRAN_SUCCESS);
enc_time[dci_msg_tx->location.L].time_us += tx->meas_time_us;
enc_time[dci_msg_tx->location.L].count++;
enc_time[dci_msg_tx->ctx.location.L].time_us += tx->meas_time_us;
enc_time[dci_msg_tx->ctx.location.L].count++;
// Init Rx MSG
srsran_pdcch_nr_res_t res = {};
@ -63,8 +63,8 @@ static int test(srsran_pdcch_nr_t* tx,
// Decode PDCCH
TESTASSERT(srsran_pdcch_nr_decode(rx, grid, ce, &dci_msg_rx, &res) == SRSRAN_SUCCESS);
dec_time[dci_msg_tx->location.L].time_us += rx->meas_time_us;
dec_time[dci_msg_tx->location.L].count++;
dec_time[dci_msg_tx->ctx.location.L].time_us += rx->meas_time_us;
dec_time[dci_msg_tx->ctx.location.L].count++;
// Assert
TESTASSERT(res.evm < 0.01f);
@ -153,6 +153,25 @@ int main(int argc, char** argv)
coreset.duration++) {
srsran_search_space_t search_space = {};
search_space.type = srsran_search_space_type_ue;
search_space.formats[search_space.nof_formats++] = srsran_dci_format_nr_0_0;
search_space.formats[search_space.nof_formats++] = srsran_dci_format_nr_1_0;
srsran_dci_cfg_nr_t dci_cfg = {};
dci_cfg.coreset0_bw = 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;
dci_cfg.monitor_common_0_0 = true;
dci_cfg.monitor_0_0_and_1_0 = true;
dci_cfg.monitor_0_1_and_1_1 = true;
// Precompute DCI sizes
srsran_dci_nr_t dci = {};
if (srsran_dci_nr_set_cfg(&dci, &dci_cfg) < SRSRAN_SUCCESS) {
ERROR("Error setting DCI configuratio");
goto clean_exit;
}
if (srsran_pdcch_nr_set_carrier(&pdcch_tx, &carrier, &coreset) < SRSRAN_SUCCESS) {
ERROR("Error setting carrier");
@ -194,11 +213,11 @@ int main(int argc, char** argv)
for (uint32_t ncce_idx = 0; ncce_idx < n; ncce_idx++) {
// Init MSG
srsran_dci_msg_nr_t dci_msg = {};
dci_msg.format = srsran_dci_format_nr_1_0;
dci_msg.rnti_type = srsran_rnti_type_c;
dci_msg.location.L = aggregation_level;
dci_msg.location.ncce = dci_locations[ncce_idx];
dci_msg.nof_bits = srsran_dci_nr_format_1_0_sizeof(&carrier, &coreset, dci_msg.rnti_type);
dci_msg.ctx.format = srsran_dci_format_nr_1_0;
dci_msg.ctx.rnti_type = srsran_rnti_type_c;
dci_msg.ctx.location.L = aggregation_level;
dci_msg.ctx.location.ncce = dci_locations[ncce_idx];
dci_msg.nof_bits = srsran_dci_nr_size(&dci, search_space.type, srsran_dci_format_nr_1_0);
// Generate random payload
for (uint32_t i = 0; i < dci_msg.nof_bits; i++) {

@ -37,13 +37,15 @@ static srsran_carrier_nr_t carrier = {
static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static uint32_t rv = 4; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static srsran_sch_grant_nr_t pdsch_grant = {};
void usage(char* prog)
static void usage(char* prog)
{
printf("Usage: %s [pTL] \n", prog);
printf("Usage: %s [prTL] \n", prog);
printf("\t-P Number of carrier PRB [Default %d]\n", carrier.nof_prb);
printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb);
printf("\t-r Redundancy version, set to 4 or higher for steering [Default %d]\n", rv);
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
srsran_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
@ -54,14 +56,20 @@ void usage(char* prog)
int parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "pmTLv")) != -1) {
while ((opt = getopt(argc, argv, "PpmTLvr")) != -1) {
switch (opt) {
case 'P':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'p':
n_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'm':
mcs = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'r':
rv = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'T':
pdsch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(argv[optind]);
break;
@ -141,12 +149,12 @@ int main(int argc, char** argv)
}
// Use grant default A time resources with m=0
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_grant) < SRSRAN_SUCCESS) {
if (srsran_ra_dl_nr_time_default_A(0, pdsch_cfg.dmrs.typeA_pos, &pdsch_cfg.grant) < SRSRAN_SUCCESS) {
ERROR("Error loading default grant");
goto clean_exit;
}
pdsch_grant.nof_layers = carrier.max_mimo_layers;
pdsch_grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_cfg.grant.nof_layers = carrier.max_mimo_layers;
pdsch_cfg.grant.dci_format = srsran_dci_format_nr_1_0;
uint32_t n_prb_start = 1;
uint32_t n_prb_end = carrier.nof_prb + 1;
@ -155,6 +163,13 @@ int main(int argc, char** argv)
n_prb_end = SRSRAN_MIN(n_prb + 1, n_prb_end);
}
uint32_t rv_start = 0;
uint32_t rv_end = 4;
if (rv < 4) {
rv_start = rv;
rv_end = rv + 1;
}
uint32_t mcs_start = 0;
uint32_t mcs_end = pdsch_cfg.sch_cfg.mcs_table == srsran_mcs_table_256qam ? 28 : 29;
if (mcs < mcs_end) {
@ -164,12 +179,20 @@ int main(int argc, char** argv)
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
for (mcs = mcs_start; mcs < mcs_end; mcs++) {
for (rv = rv_start; rv < rv_end; rv++) {
for (uint32_t n = 0; n < SRSRAN_MAX_PRB_NR; n++) {
pdsch_grant.prb_idx[n] = (n < n_prb);
pdsch_cfg.grant.prb_idx[n] = (n < n_prb);
}
if (srsran_ra_dl_nr_nof_dmrs_cdm_groups_without_data_format_1_0(&pdsch_cfg.dmrs, &pdsch_cfg.grant) <
SRSRAN_SUCCESS) {
ERROR("Error calculating number of DMRS CDM groups");
goto clean_exit;
}
srsran_sch_tb_t tb = {};
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &tb) < SRSRAN_SUCCESS) {
tb.rv = rv;
if (srsran_ra_nr_fill_tb(&pdsch_cfg, &pdsch_cfg.grant, mcs, &tb) < SRSRAN_SUCCESS) {
ERROR("Error filing tb");
goto clean_exit;
}
@ -198,6 +221,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
if (rv == 0) {
if (!crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, tb.tbs);
goto clean_exit;
@ -211,8 +235,10 @@ int main(int argc, char** argv)
srsran_vec_fprint_byte(stdout, data_rx, tb.tbs / 8);
goto clean_exit;
}
}
printf("n_prb=%d; mcs=%d; TBS=%d; PASSED!\n", n_prb, mcs, tb.tbs);
INFO("n_prb=%d; mcs=%d; rv=%d TBS=%d; PASSED!\n", n_prb, mcs, rv, tb.tbs);
}
}
}
@ -237,5 +263,5 @@ clean_exit:
srsran_softbuffer_tx_free(&softbuffer_tx);
srsran_softbuffer_rx_free(&softbuffer_rx);
return SRSRAN_SUCCESS;
return ret;
}

@ -994,8 +994,6 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin
{
uint32_t len = 0;
len = srsran_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.pucch.rnti);
if (uci_data->cfg.o_ack > 0) {
char str2[10];
srsran_vec_sprint_bin(str2, 10, uci_data->value.ack, uci_data->cfg.o_ack);

@ -26,6 +26,10 @@ add_executable(gen_ack_test gen_ack_test.c)
target_link_libraries(gen_ack_test srsran_phy)
add_test(gen_ack_test gen_ack_test)
add_executable(gen_ack_nr_test gen_ack_nr_test.c)
target_link_libraries(gen_ack_nr_test srsran_phy)
add_test(gen_ack_nr_test gen_ack_nr_test)
add_executable(pucch_resource_test pucch_resource_test.c)
target_link_libraries(pucch_resource_test srsran_phy)
add_test(pucch_resource_test pucch_resource_test)

@ -0,0 +1,150 @@
/**
*
* \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/test_common.h"
#include "srsran/phy/ue/ue_dl_nr.h"
#include <getopt.h>
static int test_case_1()
{
// Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1;
ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {};
m.value[0] = 1;
m.present = true;
m.resource.k1 = 8;
m.resource.v_dai_dl = 0;
m.value[0] = 1;
m.present = true;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5;
m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6;
m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4;
m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 3;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace
char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str);
// Generate UCI data
srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5);
return SRSRAN_SUCCESS;
}
static int test_case_2()
{
// Set configuration
srsran_ue_dl_nr_harq_ack_cfg_t cfg = {};
cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
// Generate ACK information
srsran_pdsch_ack_nr_t ack_info = {};
ack_info.nof_cc = 1;
ack_info.use_pusch = true;
srsran_pdsch_ack_m_nr_t m = {};
m.value[0] = 1;
m.present = true;
m.resource.k1 = 7;
m.resource.v_dai_dl = 1;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 6;
m.resource.v_dai_dl = 2;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 8;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 5;
m.resource.v_dai_dl = 3;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
m.resource.k1 = 4;
m.resource.v_dai_dl = 0;
TESTASSERT(srsran_ue_dl_nr_ack_insert_m(&ack_info, &m) == SRSRAN_SUCCESS);
// Print trace
char str[512] = {};
TESTASSERT(srsran_ue_dl_nr_ack_info(&ack_info, str, (uint32_t)sizeof(str)) > SRSRAN_SUCCESS);
INFO("%s", str);
// Generate UCI data
srsran_uci_data_nr_t uci_data = {};
TESTASSERT(srsran_ue_dl_nr_gen_ack(&cfg, &ack_info, &uci_data) == SRSRAN_SUCCESS);
// Assert UCI data
TESTASSERT(uci_data.cfg.o_ack == 5);
return SRSRAN_SUCCESS;
}
static void usage(char* prog)
{
printf("Usage: %s [v]\n", prog);
printf("\t-v Increase srsran_verbose\n");
}
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "v")) != -1) {
switch (opt) {
case 'v':
srsran_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char** argv)
{
parse_args(argc, argv);
// Test only until Format1B - CS
TESTASSERT(test_case_1() == SRSRAN_SUCCESS);
TESTASSERT(test_case_2() == SRSRAN_SUCCESS);
printf("Ok\n");
return SRSRAN_SUCCESS;
}

@ -23,7 +23,7 @@
#include <complex.h>
#define UE_DL_NR_PDCCH_CORR_DEFAULT_THR 0.5f
#define UE_DL_NR_PDCCH_EPRE_DEFAULT_THR -10.0f
#define UE_DL_NR_PDCCH_EPRE_DEFAULT_THR -80.0f
static int ue_dl_nr_alloc_prb(srsran_ue_dl_nr_t* q, uint32_t new_nof_prb)
{
@ -174,7 +174,9 @@ int srsran_ue_dl_nr_set_carrier(srsran_ue_dl_nr_t* q, const srsran_carrier_nr_t*
return SRSRAN_SUCCESS;
}
int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr_pdcch_cfg_t* cfg)
int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q,
const srsran_pdcch_cfg_nr_t* cfg,
const srsran_dci_cfg_nr_t* dci_cfg)
{
if (q == NULL || cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
@ -185,11 +187,20 @@ int srsran_ue_dl_nr_set_pdcch_config(srsran_ue_dl_nr_t* q, const srsran_ue_dl_nr
// iterate over all possible CORESET and initialise/update the present ones
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; i++) {
if (cfg->coreset_present[i]) {
// Skip CORESET if not present
if (!cfg->coreset_present[i]) {
continue;
}
// Initialise estimator for the CORESET
if (srsran_dmrs_pdcch_estimator_init(&q->dmrs_pdcch[i], &q->carrier, &cfg->coreset[i]) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
}
// Configure DCI sizes
if (srsran_dci_nr_set_cfg(&q->dci, dci_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
@ -229,28 +240,28 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q,
return SRSRAN_ERROR;
}
SRSRAN_MEM_ZERO(pdcch_info, srsran_ue_dl_nr_pdcch_info_t, 1);
pdcch_info->coreset_id = dci_msg->coreset_id;
pdcch_info->ss_id = dci_msg->search_space;
pdcch_info->location = dci_msg->location;
pdcch_info->dci_ctx = dci_msg->ctx;
pdcch_info->nof_bits = dci_msg->nof_bits;
srsran_dmrs_pdcch_measure_t* m = &pdcch_info->measure;
// Measures the PDCCH transmission DMRS
if (srsran_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &dci_msg->location, m) < SRSRAN_SUCCESS) {
ERROR("Error getting measure location L=%d, ncce=%d", dci_msg->location.L, dci_msg->location.ncce);
srsran_dci_location_t location = dci_msg->ctx.location;
if (srsran_dmrs_pdcch_get_measure(&q->dmrs_pdcch[coreset_id], &location, m) < SRSRAN_SUCCESS) {
ERROR("Error getting measure location L=%d, ncce=%d", location.L, location.ncce);
return SRSRAN_ERROR;
}
// If measured correlation is invalid, early return
if (!isnormal(m->norm_corr)) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;", dci_msg->location.L, dci_msg->location.ncce);
INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;", location.L, location.ncce);
return SRSRAN_SUCCESS;
}
// Compare EPRE with threshold
if (m->epre_dBfs < q->pdcch_dmrs_epre_thr) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; EPRE is too weak (%.1f<%.1f);",
dci_msg->location.L,
dci_msg->location.ncce,
location.L,
location.ncce,
m->epre_dBfs,
q->pdcch_dmrs_epre_thr);
return SRSRAN_SUCCESS;
@ -259,8 +270,8 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q,
// Compare DMRS correlation with threshold
if (m->norm_corr < q->pdcch_dmrs_corr_thr) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; Correlation is too low (%.1f<%.1f); EPRE=%+.2f; RSRP=%+.2f;",
dci_msg->location.L,
dci_msg->location.ncce,
location.L,
location.ncce,
m->norm_corr,
q->pdcch_dmrs_corr_thr,
m->epre_dBfs,
@ -269,7 +280,7 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q,
}
// Extract PDCCH channel estimates
if (srsran_dmrs_pdcch_get_ce(&q->dmrs_pdcch[coreset_id], &dci_msg->location, q->pdcch_ce) < SRSRAN_SUCCESS) {
if (srsran_dmrs_pdcch_get_ce(&q->dmrs_pdcch[coreset_id], &location, q->pdcch_ce) < SRSRAN_SUCCESS) {
ERROR("Error extracting PDCCH DMRS");
return SRSRAN_ERROR;
}
@ -302,12 +313,15 @@ static bool find_dci_msg(srsran_dci_msg_nr_t* dci_msg, uint32_t nof_dci_msg, srs
return found;
}
static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q,
static int ue_dl_nr_find_dci_ss(srsran_ue_dl_nr_t* q,
const srsran_slot_cfg_t* slot_cfg,
const srsran_search_space_t* search_space,
uint16_t rnti,
srsran_rnti_type_t rnti_type)
{
uint32_t dci_sizes[SRSRAN_DCI_NR_MAX_NOF_SIZES] = {};
uint32_t dci_sizes_count = 0;
// Select CORESET
uint32_t coreset_id = search_space->coreset_id;
if (coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET || !q->cfg.coreset_present[coreset_id]) {
@ -322,18 +336,39 @@ static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q,
return SRSRAN_ERROR;
}
// Hard-coded values
srsran_dci_format_nr_t dci_format = srsran_dci_format_nr_1_0;
// Iterate all possible formats
for (uint32_t format_idx = 0; format_idx < SRSRAN_MIN(search_space->nof_formats, SRSRAN_DCI_FORMAT_NR_COUNT);
format_idx++) {
srsran_dci_format_nr_t dci_format = search_space->formats[format_idx];
// Calculate number of DCI bits
int dci_nof_bits = srsran_dci_nr_format_1_0_sizeof(&q->carrier, coreset, rnti_type);
if (dci_nof_bits <= SRSRAN_SUCCESS) {
uint32_t dci_nof_bits = srsran_dci_nr_size(&q->dci, search_space->type, dci_format);
if (dci_nof_bits == 0) {
ERROR("Error DCI size");
return SRSRAN_ERROR;
}
// Skip DCI format if the size was already searched for the search space
bool skip = false;
for (uint32_t i = 0; i < dci_sizes_count && !skip; i++) {
if (dci_nof_bits == dci_sizes[i]) {
skip = true;
}
}
if (skip) {
continue;
}
// Append size
if (dci_sizes_count >= SRSRAN_DCI_NR_MAX_NOF_SIZES) {
ERROR("Exceed maximum number of DCI sizes");
return SRSRAN_ERROR;
}
dci_sizes[dci_sizes_count++] = dci_nof_bits;
// Iterate all possible aggregation levels
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && q->dci_msg_count < SRSRAN_MAX_DCI_MSG_NR;
for (uint32_t L = 0;
L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR && q->dl_dci_msg_count < SRSRAN_MAX_DCI_MSG_NR;
L++) {
// Calculate possible PDCCH DCI candidates
uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
@ -345,16 +380,20 @@ static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q,
}
// Iterate over the candidates
for (int ncce_idx = 0; ncce_idx < nof_candidates && q->dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; ncce_idx++) {
// Set DCI context
for (int ncce_idx = 0; ncce_idx < nof_candidates && q->dl_dci_msg_count < SRSRAN_MAX_DCI_MSG_NR; ncce_idx++) {
// Build DCI context
srsran_dci_ctx_t ctx = {};
ctx.location.L = L;
ctx.location.ncce = candidates[ncce_idx];
ctx.ss_type = search_space->type;
ctx.coreset_id = search_space->coreset_id;
ctx.rnti_type = rnti_type;
ctx.rnti = rnti;
ctx.format = dci_format;
// Build DCI message
srsran_dci_msg_nr_t dci_msg = {};
dci_msg.location.L = L;
dci_msg.location.ncce = candidates[ncce_idx];
dci_msg.search_space = search_space->type;
dci_msg.coreset_id = search_space->coreset_id;
dci_msg.rnti_type = rnti_type;
dci_msg.rnti = rnti;
dci_msg.format = dci_format;
dci_msg.ctx = ctx;
dci_msg.nof_bits = (uint32_t)dci_nof_bits;
// Find and decode PDCCH transmission in the given ncce
@ -368,35 +407,53 @@ static int ue_dl_nr_find_dl_dci_ss(srsran_ue_dl_nr_t* q,
continue;
}
// Detect if the DCI was a format 0_0
if (!srsran_dci_nr_format_1_0_valid(&dci_msg)) {
// Change grant format to 0_0
dci_msg.format = srsran_dci_format_nr_0_0;
// Detect if the DCI is the right direction
if (!srsran_dci_nr_valid_direction(&dci_msg)) {
// Change grant format direction
switch (dci_msg.ctx.format) {
case srsran_dci_format_nr_0_0:
dci_msg.ctx.format = srsran_dci_format_nr_1_0;
break;
case srsran_dci_format_nr_0_1:
dci_msg.ctx.format = srsran_dci_format_nr_1_1;
break;
case srsran_dci_format_nr_1_0:
dci_msg.ctx.format = srsran_dci_format_nr_0_0;
break;
case srsran_dci_format_nr_1_1:
dci_msg.ctx.format = srsran_dci_format_nr_0_1;
break;
default:
continue;
}
}
// If UL grant, enqueue in UL list
if (dci_msg.ctx.format == srsran_dci_format_nr_0_0 || dci_msg.ctx.format == srsran_dci_format_nr_0_1) {
// If the pending UL grant list is full or has the dci message, keep moving
if (q->pending_ul_dci_count >= SRSRAN_MAX_DCI_MSG_NR ||
find_dci_msg(q->pending_ul_dci_msg, q->pending_ul_dci_count, &dci_msg)) {
if (q->ul_dci_count >= SRSRAN_MAX_DCI_MSG_NR || find_dci_msg(q->ul_dci_msg, q->ul_dci_count, &dci_msg)) {
continue;
}
// Save the grant in the pending UL grant list
q->pending_ul_dci_msg[q->pending_ul_dci_count] = dci_msg;
q->pending_ul_dci_count++;
q->ul_dci_msg[q->ul_dci_count] = dci_msg;
q->ul_dci_count++;
// Move to next candidate
continue;
}
// Check if the grant exists already in the message list
if (find_dci_msg(q->dci_msg, q->dci_msg_count, &dci_msg)) {
// Check if the grant exists already in the DL list
if (find_dci_msg(q->dl_dci_msg, q->dl_dci_msg_count, &dci_msg)) {
// The same DCI is in the list, keep moving
continue;
}
INFO("Found DCI in L=%d,ncce=%d", dci_msg.location.L, dci_msg.location.ncce);
INFO("Found DCI in L=%d,ncce=%d", dci_msg.ctx.location.L, dci_msg.ctx.location.ncce);
// Append DCI message into the list
q->dci_msg[q->dci_msg_count] = dci_msg;
q->dci_msg_count++;
q->dl_dci_msg[q->dl_dci_msg_count] = dci_msg;
q->dl_dci_msg_count++;
}
}
}
@ -419,27 +476,27 @@ int srsran_ue_dl_nr_find_dl_dci(srsran_ue_dl_nr_t* q,
nof_dci_msg = SRSRAN_MIN(nof_dci_msg, SRSRAN_MAX_DCI_MSG_NR);
// Reset grant and blind search information counters
q->dci_msg_count = 0;
q->dl_dci_msg_count = 0;
q->pdcch_info_count = 0;
// If the UE looks for a RAR and RA search space is provided, search for it
if (q->cfg.ra_search_space_present && rnti_type == srsran_rnti_type_ra) {
// Find DCIs in the RA search space
int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type);
int ret = ue_dl_nr_find_dci_ss(q, slot_cfg, &q->cfg.ra_search_space, rnti, rnti_type);
if (ret < SRSRAN_SUCCESS) {
ERROR("Error searching RAR DCI");
return SRSRAN_ERROR;
}
} else {
// Iterate all possible common and UE search spaces
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE && q->dci_msg_count < nof_dci_msg; i++) {
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE && q->dl_dci_msg_count < nof_dci_msg; i++) {
// Skip search space if not present
if (!q->cfg.search_space_present[i]) {
continue;
}
// Find DCIs in the selected search space
int ret = ue_dl_nr_find_dl_dci_ss(q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type);
int ret = ue_dl_nr_find_dci_ss(q, slot_cfg, &q->cfg.search_space[i], rnti, rnti_type);
if (ret < SRSRAN_SUCCESS) {
ERROR("Error searching DCI");
return SRSRAN_ERROR;
@ -448,10 +505,12 @@ int srsran_ue_dl_nr_find_dl_dci(srsran_ue_dl_nr_t* q,
}
// Convert found DCI messages into DL grants
uint32_t dci_msg_count = SRSRAN_MIN(nof_dci_msg, q->dci_msg_count);
uint32_t dci_msg_count = SRSRAN_MIN(nof_dci_msg, q->dl_dci_msg_count);
for (uint32_t i = 0; i < dci_msg_count; i++) {
const srsran_coreset_t* coreset = &q->cfg.coreset[q->dci_msg[i].coreset_id];
srsran_dci_nr_format_1_0_unpack(&q->carrier, coreset, &q->dci_msg[i], &dci_dl_list[i]);
if (srsran_dci_nr_dl_unpack(&q->dci, &q->dl_dci_msg[i], &dci_dl_list[i]) < SRSRAN_SUCCESS) {
ERROR("Error unpacking grant %d;", i);
return SRSRAN_ERROR;
}
}
return (int)dci_msg_count;
@ -472,15 +531,14 @@ int srsran_ue_dl_nr_find_ul_dci(srsran_ue_dl_nr_t* q,
}
// Get DCI messages from the pending list
for (uint32_t i = 0; i < q->pending_ul_dci_count && count < nof_dci_msg; i++) {
srsran_dci_msg_nr_t* dci_msg = &q->pending_ul_dci_msg[i];
for (uint32_t i = 0; i < q->ul_dci_count && count < nof_dci_msg; i++) {
srsran_dci_msg_nr_t* dci_msg = &q->ul_dci_msg[i];
if (dci_msg->rnti_type != rnti_type || dci_msg->rnti != rnti) {
if (dci_msg->ctx.rnti_type != rnti_type || dci_msg->ctx.rnti != rnti) {
continue;
}
const srsran_coreset_t* coreset = &q->cfg.coreset[dci_msg->coreset_id];
if (srsran_dci_nr_format_0_0_unpack(&q->carrier, coreset, dci_msg, &dci_ul_list[count]) < SRSRAN_SUCCESS) {
if (srsran_dci_nr_ul_unpack(&q->dci, dci_msg, &dci_ul_list[count]) < SRSRAN_SUCCESS) {
ERROR("Unpacking DCI 0_0");
continue;
}
@ -488,7 +546,7 @@ int srsran_ue_dl_nr_find_ul_dci(srsran_ue_dl_nr_t* q,
}
// Reset pending UL grant list
q->pending_ul_dci_count = 0;
q->ul_dci_count = 0;
return count;
}
@ -647,7 +705,7 @@ static int ue_dl_nr_gen_ack_type2(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
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->format == srsran_dci_format_nr_1_0) {
if (dci_dl->ctx.format == srsran_dci_format_nr_1_0) {
return (int)dci_dl->harq_feedback + 1;
}
@ -677,10 +735,10 @@ int srsran_ue_dl_nr_pdsch_ack_resource(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg
}
// Fill PDSCH resource
pdsch_ack_resource->dci_format_1_1 = (dci_dl->format == srsran_dci_format_nr_1_1);
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->rnti;
pdsch_ack_resource->rnti = dci_dl->ctx.rnti;
pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource;
return SRSRAN_SUCCESS;
@ -696,14 +754,14 @@ int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
}
// According TS 38.213 9.1.2 Type-1 HARQ-ACK codebook determination
if (cfg->pdsch_harq_ack_codebook == srsran_pdsch_harq_ack_codebook_semi_static) {
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->pdsch_harq_ack_codebook == srsran_pdsch_harq_ack_codebook_dynamic) {
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);
}
@ -711,3 +769,72 @@ int srsran_ue_dl_nr_gen_ack(const srsran_ue_dl_nr_harq_ack_cfg_t* cfg,
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, 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;
}

@ -233,6 +233,7 @@ void srsran_ue_ul_nr_free(srsran_ue_ul_nr_t* q)
if (q->sf_symbols[0] != NULL) {
free(q->sf_symbols[0]);
}
srsran_pucch_nr_free(&q->pucch);
srsran_pusch_nr_free(&q->pusch);
srsran_dmrs_sch_free(&q->dmrs);

@ -30,7 +30,8 @@ set(SOURCES gtpu.cc
rlc_am_lte.cc
pdcp_entity_nr.cc
rlc_um_nr.cc
rlc_am_nr.cc)
rlc_am_nr.cc
bearer_mem_pool.cc)
add_library(srsran_upper STATIC ${SOURCES})
target_link_libraries(srsran_upper srsran_common srsran_asn1)

@ -0,0 +1,44 @@
/**
*
* \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/upper/bearer_mem_pool.h"
#include "srsran/adt/pool/batch_mem_pool.h"
#include "srsran/upper/rlc_am_lte.h"
#include "srsran/upper/rlc_um_lte.h"
#include "srsran/upper/rlc_um_nr.h"
namespace srsran {
srsran::background_mem_pool* get_bearer_pool()
{
static background_mem_pool pool(
4, std::max(std::max(sizeof(rlc_am_lte), sizeof(rlc_um_lte)), sizeof(rlc_um_nr)), 8, 8);
return &pool;
}
void reserve_rlc_memblocks(size_t nof_blocks)
{
srsran::background_mem_pool* pool = get_bearer_pool();
while (pool->cache_size() < nof_blocks) {
pool->allocate_batch();
}
}
void* allocate_rlc_bearer(std::size_t sz)
{
return get_bearer_pool()->allocate_node(sz);
}
void deallocate_rlc_bearer(void* p)
{
get_bearer_pool()->deallocate_node(p);
}
} // namespace srsran

@ -104,7 +104,12 @@ void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg)
if (not valid_lcid(lcid)) {
std::unique_ptr<pdcp_entity_base> entity;
// For now we create an pdcp entity lte for nr due to it's maturity
entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid, cfg});
entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid});
if (not entity->configure(cfg)) {
logger.error("Can not configure PDCP entity");
return;
}
if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) {
logger.error("Error inserting PDCP entity in to array.");
return;
@ -126,10 +131,17 @@ void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg)
void pdcp::add_bearer_mrb(uint32_t lcid, pdcp_config_t cfg)
{
if (not valid_mch_lcid(lcid)) {
std::unique_ptr<pdcp_entity_lte> entity;
entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid});
if(not entity->configure(cfg)){
logger.error("Can not configure PDCP entity");
return;
}
if (not pdcp_array_mrb
.insert(std::make_pair(
lcid,
std::unique_ptr<pdcp_entity_lte>(new pdcp_entity_lte(rlc, rrc, gw, task_sched, logger, lcid, cfg))))
std::move(entity)))
.second) {
logger.error("Error inserting PDCP entity in to array.");
return;

@ -38,29 +38,36 @@ pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_,
srsue::gw_interface_pdcp* gw_,
srsran::task_sched_handle task_sched_,
srslog::basic_logger& logger,
uint32_t lcid_,
pdcp_config_t cfg_) :
uint32_t lcid_) :
pdcp_entity_base(task_sched_, logger), rlc(rlc_), rrc(rrc_), gw(gw_)
{
lcid = lcid_;
cfg = cfg_;
active = true;
// Initial state
integrity_direction = DIRECTION_NONE;
encryption_direction = DIRECTION_NONE;
if (is_srb()) {
reordering_window = 0;
} else if (is_drb()) {
reordering_window = 2048;
}
// Initial state
st.next_pdcp_tx_sn = 0;
st.tx_hfn = 0;
st.rx_hfn = 0;
st.next_pdcp_rx_sn = 0;
lcid = lcid_;
}
pdcp_entity_lte::~pdcp_entity_lte()
{
reset();
}
bool pdcp_entity_lte::configure(const pdcp_config_t& cnfg_)
{
cfg = cnfg_;
maximum_pdcp_sn = (1u << cfg.sn_len) - 1u;
st.last_submitted_pdcp_rx_sn = maximum_pdcp_sn;
if (is_srb()) {
reordering_window = 0;
} else if (is_drb()) {
reordering_window = 2048;
}
if (is_drb() && not rlc->rb_is_um(lcid) && cfg.discard_timer == pdcp_discard_timer_t::infinity) {
logger.warning(
@ -89,14 +96,11 @@ pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_,
// Check supported config
if (!check_valid_config()) {
srsran::console("Warning: Invalid PDCP config.\n");
return false;
}
active = true;
return true;
}
pdcp_entity_lte::~pdcp_entity_lte()
{
reset();
}
// Reestablishment procedure: 36.323 5.2
void pdcp_entity_lte::reestablish()
{

@ -29,8 +29,7 @@ pdcp_entity_nr::pdcp_entity_nr(srsue::rlc_interface_pdcp* rlc_,
srsue::gw_interface_pdcp* gw_,
srsran::task_sched_handle task_sched_,
srslog::basic_logger& logger,
uint32_t lcid_,
pdcp_config_t cfg_) :
uint32_t lcid_) :
pdcp_entity_base(task_sched_, logger),
rlc(rlc_),
rrc(rrc_),
@ -38,11 +37,22 @@ pdcp_entity_nr::pdcp_entity_nr(srsue::rlc_interface_pdcp* rlc_,
reordering_fnc(new pdcp_entity_nr::reordering_callback(this))
{
lcid = lcid_;
cfg = cfg_;
active = true;
integrity_direction = DIRECTION_NONE;
encryption_direction = DIRECTION_NONE;
}
pdcp_entity_nr::~pdcp_entity_nr() {}
// Reestablishment procedure: 38.323 5.2
void pdcp_entity_nr::reestablish()
{
logger.info("Re-establish %s with bearer ID: %d", rrc->get_rb_name(lcid).c_str(), cfg.bearer_id);
// TODO
}
bool pdcp_entity_nr::configure(const pdcp_config_t& cnfg_)
{
cfg = cnfg_;
window_size = 1 << (cfg.sn_len - 1);
// Timers
@ -52,15 +62,8 @@ pdcp_entity_nr::pdcp_entity_nr(srsue::rlc_interface_pdcp* rlc_,
if (static_cast<uint32_t>(cfg.t_reordering) > 0) {
reordering_timer.set(static_cast<uint32_t>(cfg.t_reordering), *reordering_fnc);
}
}
pdcp_entity_nr::~pdcp_entity_nr() {}
// Reestablishment procedure: 38.323 5.2
void pdcp_entity_nr::reestablish()
{
logger.info("Re-establish %s with bearer ID: %d", rrc->get_rb_name(lcid).c_str(), cfg.bearer_id);
// TODO
active = true;
return true;
}
// Used to stop/pause the entity (called on RRC conn release)

@ -303,6 +303,8 @@ int rlc::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
logger.warning("LCID %d doesn't exist.", lcid);
}
srsran_expect(ret <= nof_bytes, "Created too big RLC PDU (%d > %d)", ret, nof_bytes);
return ret;
}
@ -318,6 +320,8 @@ int rlc::read_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes)
logger.warning("LCID %d doesn't exist.", lcid);
}
srsran_expect(ret <= nof_bytes, "Created too big RLC PDU for MCH (%d > %d)", ret, nof_bytes);
return ret;
}

@ -858,11 +858,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte
retx_queue.front().so_start = retx.so_end;
}
// increment counter for retx of first segment
if (retx.so_start == 0) {
tx_window[retx.sn].retx_count++;
}
check_sn_reached_max_retx(retx.sn);
// Write header and pdu
@ -1149,7 +1145,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
update_vt_a = false;
if (tx_window.has_sn(i)) {
auto& pdu = tx_window[i];
if (!retx_queue.has_sn(i)) {
if (not retx_queue.has_sn(i)) {
rlc_amd_retx_t& retx = retx_queue.push();
srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i);
retx.sn = i;
@ -1185,6 +1181,8 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
pdu.buf->N_bytes);
}
}
} else {
logger.info("%s NACKed SN=%d already considered for retransmission", RB_NAME, i);
}
} else {
logger.warning("%s NACKed SN=%d already removed from Tx window", RB_NAME, i);
@ -2139,6 +2137,7 @@ buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(max_buffer_idx
void buffered_pdcp_pdu_list::clear()
{
count = 0;
for (auto& b : buffered_pdus) {
b.sn = invalid_sn;
b.fully_acked = false;

@ -21,6 +21,7 @@
#include "srsran/adt/pool/fixed_size_pool.h"
#include "srsran/adt/pool/mem_pool.h"
#include "srsran/adt/pool/obj_pool.h"
#include "srsran/common/test_common.h"
class C
@ -30,13 +31,14 @@ public:
~C() { dtor_counter++; }
void* operator new(size_t sz);
void* operator new(size_t sz, void*& ptr) { return ptr; }
void operator delete(void* ptr)noexcept;
static int default_ctor_counter;
static int dtor_counter;
static std::atomic<int> default_ctor_counter;
static std::atomic<int> dtor_counter;
};
int C::default_ctor_counter = 0;
int C::dtor_counter = 0;
std::atomic<int> C::default_ctor_counter(0);
std::atomic<int> C::dtor_counter(0);
srsran::big_obj_pool<C> pool;
@ -50,7 +52,7 @@ void C::operator delete(void* ptr)noexcept
pool.deallocate_node(ptr);
}
int test_nontrivial_obj_pool()
void test_nontrivial_obj_pool()
{
// No object creation on reservation
{
@ -81,8 +83,6 @@ int test_nontrivial_obj_pool()
}
TESTASSERT(C::default_ctor_counter == 1);
TESTASSERT(C::dtor_counter == 1);
return SRSRAN_SUCCESS;
}
struct BigObj {
@ -124,6 +124,7 @@ void test_fixedsize_pool()
fixed_pool->print_all_buffers();
}
fixed_pool->print_all_buffers();
TESTASSERT(C::default_ctor_counter == C::dtor_counter);
// TEST: one thread allocates, and the other deallocates
{
@ -147,15 +148,47 @@ void test_fixedsize_pool()
t.join();
}
fixed_pool->print_all_buffers();
TESTASSERT(C::default_ctor_counter == C::dtor_counter);
}
struct D : public C {
char val = '\0';
};
void test_background_pool()
{
C::default_ctor_counter = 0;
C::dtor_counter = 0;
{
auto init_D_val = [](void* ptr) {
new (ptr) D();
static_cast<D*>(ptr)->val = 'c';
};
srsran::background_obj_pool<D> obj_pool(16, 4, 16, init_D_val);
TESTASSERT(obj_pool.cache_size() == 16);
std::vector<srsran::unique_pool_ptr<D> > objs;
for (size_t i = 0; i < 16 - 4; ++i) {
objs.push_back(obj_pool.make());
}
TESTASSERT(
std::all_of(objs.begin(), objs.end(), [](const srsran::unique_pool_ptr<D>& d) { return d->val == 'c'; }));
TESTASSERT(C::default_ctor_counter == 16);
// This will trigger a new batch allocation in the background
objs.push_back(obj_pool.make());
}
TESTASSERT(C::dtor_counter == C::default_ctor_counter);
}
int main(int argc, char** argv)
{
srsran::test_init(argc, argv);
TESTASSERT(test_nontrivial_obj_pool() == SRSRAN_SUCCESS);
test_nontrivial_obj_pool();
test_fixedsize_pool();
test_background_pool();
srsran::console("Success\n");
printf("Success\n");
return 0;
}

@ -119,7 +119,7 @@ int make_phy_harq_ack_cfg_test()
srsran_ue_dl_nr_harq_ack_cfg_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(srsran_ue_dl_nr_harq_ack_cfg.pdsch_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);
return SRSRAN_SUCCESS;
}

@ -36,6 +36,25 @@ using namespace asn1::rrc;
} \
}
int rrc_nr_test_scg_fail_packing()
{
ul_dcch_msg_s ul_dcch_msg;
scg_fail_info_nr_r15_s& scg_fail_info_nr = ul_dcch_msg.msg.set_msg_class_ext().set_c2().set_scg_fail_info_nr_r15();
scg_fail_info_nr.crit_exts.set_c1();
scg_fail_info_nr.crit_exts.c1().set_scg_fail_info_nr_r15();
scg_fail_info_nr.crit_exts.c1().scg_fail_info_nr_r15().fail_report_scg_nr_r15_present = true;
scg_fail_info_nr.crit_exts.c1().scg_fail_info_nr_r15().fail_report_scg_nr_r15.fail_type_r15 =
fail_report_scg_nr_r15_s::fail_type_r15_opts::options::scg_recfg_fail;
uint8_t buf[64];
bzero(buf, sizeof(buf));
asn1::bit_ref bref(buf, sizeof(buf));
TESTASSERT(ul_dcch_msg.pack(bref) == SRSRAN_SUCCESS);
bref.align_bytes_zero();
uint32_t cap_len = (uint32_t)bref.distance_bytes(buf);
return SRSRAN_SUCCESS;
}
int rrc_ue_cap_info_test(srsran::mac_pcap* pcap)
{
auto& rrc_logger = srslog::fetch_basic_logger("RRC", false);
@ -169,9 +188,10 @@ int main(int argc, char** argv)
pcap.open("ul_dcch.pcap");
TESTASSERT(rrc_ue_cap_info_test(&pcap) == 0);
#else
TESTASSERT(rrc_ue_cap_info_test(NULL) == 0);
// TESTASSERT(rrc_ue_cap_info_test(NULL) == 0);
#endif
TESTASSERT(pack_fail_test() == -1);
TESTASSERT(rrc_nr_test_scg_fail_packing() == SRSRAN_SUCCESS)
#if PCAP
pcap.close();

@ -20,15 +20,32 @@
*/
#include "srsran/common/network_utils.h"
#include "srsran/common/task_scheduler.h"
#include "srsran/common/test_common.h"
#include <atomic>
#include <iostream>
#define TESTASSERT(cond) \
do { \
if (!(cond)) { \
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
return -1; \
} \
} while (0)
struct rx_thread_tester {
srsran::task_scheduler task_sched;
srsran::task_queue_handle task_queue;
std::atomic<bool> stop_token;
std::thread t;
rx_thread_tester() :
task_queue(task_sched.make_task_queue()), t([this]() {
stop_token.store(false);
while (not stop_token.load(std::memory_order_relaxed)) {
task_sched.run_pending_tasks();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
})
{}
~rx_thread_tester()
{
stop_token.store(true, std::memory_order_relaxed);
t.join();
}
};
int test_socket_handler()
{
@ -36,8 +53,8 @@ int test_socket_handler()
int counter = 0;
srsran::socket_handler_t server_socket, client_socket, client_socket2;
srsran::rx_multisocket_handler sockhandler("RXSOCKETS", logger);
srsran::unique_socket server_socket, client_socket, client_socket2;
srsran::socket_manager sockhandler;
int server_port = 36412;
const char* server_addr = "127.0.100.1";
using namespace srsran::net_utils;
@ -59,7 +76,9 @@ int test_socket_handler()
counter++;
}
};
sockhandler.add_socket_sctp_pdu_handler(server_socket.fd(), pdu_handler);
rx_thread_tester rx_tester;
sockhandler.add_socket_handler(server_socket.fd(),
srsran::make_sctp_sdu_handler(logger, rx_tester.task_queue, pdu_handler));
uint8_t buf[128] = {};
int32_t nof_counts = 5;
@ -69,7 +88,7 @@ int test_socket_handler()
for (int32_t i = 0; i < nof_counts; ++i) {
buf[i] = i;
// Round-robin between clients
srsran::socket_handler_t* chosen = &client_socket;
srsran::unique_socket* chosen = &client_socket;
if (i % 2 == 1) {
chosen = &client_socket2;
}

@ -335,6 +335,26 @@ int mac_rar_pdu_unpack_test8()
return SRSRAN_SUCCESS;
}
int mac_dl_sch_pdu_unpack_test9()
{
// MAC PDU with Timing Advance CE and padding
uint8_t tv[] = {0x3d, 0x1f, 0x3f, 0x00, 0x00, 0x00};
if (pcap_handle) {
pcap_handle->write_dl_crnti_nr(tv, sizeof(tv), PCAP_CRNTI, true, PCAP_TTI);
}
srsran::mac_sch_pdu_nr pdu;
pdu.unpack(tv, sizeof(tv));
TESTASSERT(pdu.get_num_subpdus() == 2);
mac_sch_subpdu_nr subpdu = pdu.get_subpdu(0);
TESTASSERT(subpdu.get_ta().tag_id == 0);
TESTASSERT(subpdu.get_ta().ta_command == 31);
return SRSRAN_SUCCESS;
}
int mac_ul_sch_pdu_unpack_test1()
{
// UL-SCH MAC PDU with fixed-size CE and DL-SCH subheader with 16-bit length field
@ -666,6 +686,11 @@ int main(int argc, char** argv)
return SRSRAN_ERROR;
}
if (mac_dl_sch_pdu_unpack_test9()) {
fprintf(stderr, "mac_dl_sch_pdu_unpack_test9() failed.\n");
return SRSRAN_ERROR;
}
if (mac_ul_sch_pdu_unpack_test1()) {
fprintf(stderr, "mac_ul_sch_pdu_unpack_test1() failed.\n");
return SRSRAN_ERROR;

@ -41,6 +41,7 @@ static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {};
static uint32_t nof_slots = 10;
static uint32_t rv_idx = 0;
static void usage(char* prog)
{
@ -49,6 +50,7 @@ static void usage(char* prog)
printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb);
printf("\t-n Number of slots to simulate [Default %d]\n", nof_slots);
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
printf("\t-r Redundancy version, set to >28 for steering [Default %d]\n", mcs);
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
srsran_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
printf("\t-R Reserve RE: [rb_begin] [rb_end] [rb_stride] [sc_mask] [symbol_mask]\n");
@ -59,7 +61,7 @@ static void usage(char* prog)
static int parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "RPpmnTLv")) != -1) {
while ((opt = getopt(argc, argv, "rRPpmnTLv")) != -1) {
switch (opt) {
case 'P':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
@ -73,6 +75,9 @@ static int parse_args(int argc, char** argv)
case 'm':
mcs = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'r':
rv_idx = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'T':
pdsch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(argv[optind]);
break;
@ -122,12 +127,12 @@ static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl,
// Hard-coded values
srsran_dci_dl_nr_t dci_dl = {};
dci_dl.rnti = pdsch_cfg.grant.rnti;
dci_dl.rnti_type = pdsch_cfg.grant.rnti_type;
dci_dl.format = srsran_dci_format_nr_1_0;
dci_dl.location = *dci_location;
dci_dl.search_space = search_space->type;
dci_dl.coreset_id = 1;
dci_dl.ctx.rnti = pdsch_cfg.grant.rnti;
dci_dl.ctx.rnti_type = pdsch_cfg.grant.rnti_type;
dci_dl.ctx.format = srsran_dci_format_nr_1_0;
dci_dl.ctx.location = *dci_location;
dci_dl.ctx.ss_type = search_space->type;
dci_dl.ctx.coreset_id = 1;
dci_dl.freq_domain_assigment = 0;
dci_dl.time_domain_assigment = 0;
dci_dl.vrb_to_prb_mapping = 0;
@ -220,7 +225,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
srsran_ue_dl_nr_pdcch_cfg_t pdcch_cfg = {};
srsran_pdcch_cfg_nr_t pdcch_cfg = {};
// Configure CORESET
srsran_coreset_t* coreset = &pdcch_cfg.coreset[1];
@ -236,6 +241,9 @@ int main(int argc, char** argv)
search_space->id = 0;
search_space->coreset_id = 1;
search_space->type = srsran_search_space_type_common_3;
search_space->formats[0] = srsran_dci_format_nr_0_0;
search_space->formats[1] = srsran_dci_format_nr_1_0;
search_space->nof_formats = 2;
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
search_space->nof_candidates[L] = srsran_pdcch_nr_max_candidates_coreset(coreset, L);
}
@ -253,9 +261,14 @@ int main(int argc, char** argv)
if (srsran_ue_dl_nr_set_carrier(&ue_dl, &carrier)) {
ERROR("Error setting SCH NR carrier");
goto clean_exit;
goto clean_exit;
}
if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg)) {
srsran_dci_cfg_nr_t dci_cfg = {};
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.monitor_common_0_0 = true;
if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg, &dci_cfg)) {
ERROR("Error setting CORESET");
goto clean_exit;
}
@ -265,7 +278,7 @@ int main(int argc, char** argv)
goto clean_exit;
}
if (srsran_enb_dl_nr_set_coreset(&enb_dl, coreset)) {
if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &pdcch_cfg, &dci_cfg)) {
ERROR("Error setting CORESET");
goto clean_exit;
}
@ -307,6 +320,7 @@ int main(int argc, char** argv)
pdsch_cfg.grant.nof_dmrs_cdm_groups_without_data = 1;
pdsch_cfg.grant.rnti_type = srsran_rnti_type_c;
pdsch_cfg.grant.rnti = 0x4601;
pdsch_cfg.grant.tb[0].rv = rv_idx;
uint32_t n_prb_start = 1;
uint32_t n_prb_end = carrier.nof_prb + 1;
@ -349,10 +363,14 @@ int main(int argc, char** argv)
}
// Compute PDCCH candidate locations
uint32_t L = 0;
uint32_t L = 1;
uint32_t ncce_candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_candidates = srsran_pdcch_nr_locations_coreset(
coreset, search_space, pdsch_cfg.grant.rnti, L, slot.idx, ncce_candidates);
int nof_candidates = srsran_pdcch_nr_locations_coreset(coreset,
search_space,
pdsch_cfg.grant.rnti,
L,
SRSRAN_SLOT_NR_MOD(carrier.numerology, slot.idx),
ncce_candidates);
if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error getting PDCCH candidates");
goto clean_exit;
@ -391,6 +409,8 @@ int main(int argc, char** argv)
goto clean_exit;
}
// Check CRC only for RV=0
if (rv_idx == 0) {
if (!pdsch_res[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs);
goto clean_exit;
@ -404,6 +424,7 @@ int main(int argc, char** argv)
srsran_vec_fprint_byte(stdout, data_rx[0], pdsch_cfg.grant.tb[0].tbs / 8);
goto clean_exit;
}
}
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res[0].evm);

@ -69,8 +69,9 @@ class pdcp_lte_test_helper
{
public:
pdcp_lte_test_helper(srsran::pdcp_config_t cfg, srsran::as_security_config_t sec_cfg_, srslog::basic_logger& logger) :
rlc(logger), rrc(logger), gw(logger), pdcp(&rlc, &rrc, &gw, &stack.task_sched, logger, 0, cfg)
rlc(logger), rrc(logger), gw(logger), pdcp(&rlc, &rrc, &gw, &stack.task_sched, logger, 0)
{
pdcp.configure(cfg);
pdcp.config_security(sec_cfg_);
pdcp.enable_integrity(srsran::DIRECTION_TXRX);
pdcp.enable_encryption(srsran::DIRECTION_TXRX);

@ -97,8 +97,9 @@ class pdcp_nr_test_helper
{
public:
pdcp_nr_test_helper(srsran::pdcp_config_t cfg, srsran::as_security_config_t sec_cfg_, srslog::basic_logger& logger) :
rlc(logger), rrc(logger), gw(logger), pdcp(&rlc, &rrc, &gw, &stack.task_sched, logger, 0, cfg)
rlc(logger), rrc(logger), gw(logger), pdcp(&rlc, &rrc, &gw, &stack.task_sched, logger, 0)
{
pdcp.configure(cfg);
pdcp.config_security(sec_cfg_);
pdcp.enable_integrity(srsran::DIRECTION_TXRX);
pdcp.enable_encryption(srsran::DIRECTION_TXRX);

@ -26,6 +26,7 @@
INCLUDES
*******************************************************************************/
#include <memory>
#include <stdint.h>
namespace srsenb {

@ -0,0 +1,48 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_RNTI_POOL_H
#define SRSRAN_RNTI_POOL_H
#include "srsran/adt/pool/pool_interface.h"
#include "srsran/phy/common/phy_common.h"
#include <memory>
namespace srsenb {
// Allocation of objects in rnti-dedicated memory pool
void reserve_rnti_memblocks(size_t nof_blocks);
void* allocate_rnti_dedicated_mem(uint16_t rnti, std::size_t size, std::size_t align);
void deallocate_rnti_dedicated_mem(uint16_t rnti, void* p);
template <typename T>
using unique_rnti_ptr = srsran::unique_pool_ptr<T>;
template <typename T, typename... Args>
unique_rnti_ptr<T> make_rnti_obj(uint16_t rnti, Args&&... args)
{
void* block = allocate_rnti_dedicated_mem(rnti, sizeof(T), alignof(T));
if (block == nullptr) {
// allocated with "new" as a fallback
return unique_rnti_ptr<T>(new T(std::forward<Args>(args)...), std::default_delete<T>());
}
// allocation using rnti-dedicated memory pool was successful
new (block) T(std::forward<Args>(args)...);
return unique_rnti_ptr<T>(static_cast<T*>(block), [rnti](T* ptr) {
ptr->~T();
deallocate_rnti_dedicated_mem(rnti, ptr);
});
}
} // namespace srsenb
#endif // SRSRAN_RNTI_POOL_H

@ -23,8 +23,10 @@
#define SRSENB_NR_CC_WORKER_H
#include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include "srsran/phy/enb/enb_dl_nr.h"
#include "srsran/srslog/srslog.h"
#include "srsran/srsran.h"
#include <array>
#include <vector>
@ -36,15 +38,11 @@ typedef struct {
srsran_enb_dl_nr_args_t dl;
} phy_nr_args_t;
typedef struct {
srsran_sch_hl_cfg_nr_t pdsch;
} phy_nr_cfg_t;
class phy_nr_state
{
public:
phy_nr_args_t args = {};
phy_nr_cfg_t cfg = {};
srsran::phy_cfg_nr_t cfg = {};
phy_nr_state()
{
@ -53,8 +51,7 @@ public:
args.dl.nof_tx_antennas = 1;
args.dl.pdsch.measure_evm = true;
args.dl.pdsch.measure_time = true;
args.dl.pdsch.sch.disable_simd = true;
cfg.pdsch.sch_cfg.mcs_table = srsran_mcs_table_256qam;
args.dl.pdsch.sch.disable_simd = false;
}
};

@ -27,6 +27,7 @@
#include "srsran/common/threads.h"
#include "srsran/interfaces/enb_phy_interfaces.h"
#include "srsran/srslog/srslog.h"
#include <atomic>
// Setting ENABLE_PRACH_GUI to non zero enables a GUI showing signal received in the PRACH window.
#define ENABLE_PRACH_GUI 0
@ -97,7 +98,7 @@ private:
stack_interface_phy_lte* stack = nullptr;
float max_prach_offset_us = 0.0f;
bool initiated = false;
bool running = false;
std::atomic<bool> running;
uint32_t nof_sf = 0;
uint32_t sf_cnt = 0;
uint32_t nof_workers = 0;

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

Loading…
Cancel
Save