Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srslte/common/log.h
#	lib/include/srslte/common/log_filter.h
#	lib/include/srslte/common/logger.h
#	lib/include/srslte/common/logger_srslog_wrapper.h
#	lib/include/srslte/common/logmap.h
#	lib/src/common/log_filter.cc
#	lib/src/common/logger_srslog_wrapper.cc
#	lib/src/common/logmap.cc
#	lib/test/common/log_filter_test.cc
#	lib/test/common/test_common_test.cc
master
srsLTE codebot 4 years ago committed by Your Name
commit 6ccccade9e

@ -20,6 +20,8 @@ Checks: '*,-fuchsia-*,
-google-runtime-references,-google-readability-casting,-google-build-using-namespace, -google-runtime-references,-google-readability-casting,-google-build-using-namespace,
google-default-arguments,-cppcoreguidelines-pro-bounds-pointer-arithmetic, google-default-arguments,-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cert-err58-cpp, -cert-err58-cpp,
-misc-non-private-member-variables-in-classes,-altera-struct-pack-align,-readability-uppercase-literal-suffix,
-cppcoreguidelines-non-private-member-variables-in-classes,
readability-identifier-naming' readability-identifier-naming'
HeaderFilterRegex: '' HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false AnalyzeTemporaryDtors: false

@ -92,6 +92,8 @@ option(ENABLE_TIMEPROF "Enable time profiling" ON)
option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF) option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF)
option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" OFF)
# Users that want to try this feature need to make sure the lto plugin is # Users that want to try this feature need to make sure the lto plugin is
# loaded by bintools (ar, nm, ...). Older versions of bintools will not do # loaded by bintools (ar, nm, ...). Older versions of bintools will not do
# it automatically so it is necessary to use the gcc wrappers of the compiler # it automatically so it is necessary to use the gcc wrappers of the compiler
@ -105,6 +107,17 @@ else(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.") set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.")
endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
# On RAM constrained (embedded) systems it may be useful to limit parallel compilation with, e.g. -DPARALLEL_COMPILE_JOBS=1
if (PARALLEL_COMPILE_JOBS)
set(CMAKE_JOB_POOL_COMPILE compile_job_pool${CMAKE_CURRENT_SOURCE_DIR})
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_COMPILE ${CMAKE_JOB_POOL_COMPILE})
set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_COMPILE}=${PARALLEL_COMPILE_JOBS})
message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Limiting compiler jobs to ${PARALLEL_COMPILE_JOBS}")
endif ()
if (ENABLE_SRSLOG_TRACING)
add_definitions(-DENABLE_SRSLOG_EVENT_TRACE)
endif (ENABLE_SRSLOG_TRACING)
######################################################################## ########################################################################
# Find dependencies # Find dependencies

@ -23,6 +23,7 @@
#define SRSLTE_DYN_BITSET_H #define SRSLTE_DYN_BITSET_H
#include "adt_utils.h" #include "adt_utils.h"
#include "srslte/srslog/bundled/fmt/format.h"
#include <cstdint> #include <cstdint>
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
@ -41,9 +42,9 @@ class bounded_bitset
static const size_t bits_per_word = 8 * sizeof(word_t); static const size_t bits_per_word = 8 * sizeof(word_t);
public: public:
constexpr bounded_bitset() : buffer(), cur_size(0) {} constexpr bounded_bitset() = default;
constexpr explicit bounded_bitset(size_t cur_size_) : buffer(), cur_size(cur_size_) {} constexpr explicit bounded_bitset(size_t cur_size_) : cur_size(cur_size_) {}
constexpr size_t max_size() const noexcept { return N; } constexpr size_t max_size() const noexcept { return N; }
@ -62,7 +63,7 @@ public:
cur_size = new_size; cur_size = new_size;
sanitize_(); sanitize_();
for (size_t i = nof_words_(); i < max_nof_words_(); ++i) { for (size_t i = nof_words_(); i < max_nof_words_(); ++i) {
get_word_(i) = static_cast<word_t>(0); buffer[i] = static_cast<word_t>(0);
} }
} }
@ -172,10 +173,12 @@ public:
size_t result = 0; size_t result = 0;
for (size_t i = 0; i < nof_words_(); i++) { for (size_t i = 0; i < nof_words_(); i++) {
// result += __builtin_popcountl(buffer[i]); // result += __builtin_popcountl(buffer[i]);
word_t w = buffer[i]; // Note: use an "int" for count triggers popcount optimization if SSE instructions are enabled.
for (; w; w >>= 1u) { int c = 0;
result += (w & 1u); for (word_t w = buffer[i]; w > 0; c++) {
w &= w - 1;
} }
result += c;
} }
return result; return result;
} }
@ -228,24 +231,25 @@ public:
return ret; return ret;
} }
std::string to_string() const template <typename OutputIt>
OutputIt to_string(OutputIt&& mem_buffer) const
{ {
if (size() == 0) {
return mem_buffer;
}
std::string s; std::string s;
s.assign(size(), '0'); s.assign(size(), '0');
if (not reversed) { if (not reversed) {
for (size_t i = size(); i > 0; --i) { for (size_t i = size(); i > 0; --i) {
if (test(i - 1)) { fmt::format_to(mem_buffer, "{}", test(i - 1) ? '1' : '0');
s[size() - i] = '1';
}
} }
} else { } else {
for (size_t i = 0; i < size(); ++i) { for (size_t i = 0; i < size(); ++i) {
if (test(i)) { fmt::format_to(mem_buffer, "{}", test(i) ? '1' : '0');
s[i] = '1';
}
} }
} }
return s; return mem_buffer;
} }
uint64_t to_uint64() const uint64_t to_uint64() const
@ -257,24 +261,26 @@ public:
return get_word_(0); return get_word_(0);
} }
std::string to_hex() const noexcept template <typename OutputIt>
OutputIt to_hex(OutputIt&& mem_buffer) const noexcept
{ {
size_t nof_digits = (size() - 1) / 4 + 1; if (size() == 0) {
char cstr[ceil_div(ceil_div(N, bits_per_word) * bits_per_word, 4) + 1]; return mem_buffer;
size_t count = 0;
for (int i = nof_words_() - 1; i >= 0; --i) {
count += sprintf(&cstr[count], "%016" PRIx64, buffer[i]);
} }
// first word may not print 16 hex digits
size_t skip = nof_words_() * bits_per_word / 4 - nof_digits; int i = nof_words_() - 1;
// printf("bitstring: %s\n", to_string().c_str()); size_t rem_symbols = ceil_div((size() - (size() / bits_per_word) * bits_per_word), 4U);
return std::string(&cstr[skip], &cstr[nof_digits + skip + 1]); fmt::format_to(mem_buffer, "{:0>{}x}", buffer[i], rem_symbols);
// remaining words will occupy 16 hex digits
for (--i; i >= 0; --i) {
fmt::format_to(mem_buffer, "{:0>16x}", buffer[i]);
}
return mem_buffer;
} }
private: private:
word_t buffer[(N - 1) / bits_per_word + 1]; word_t buffer[(N - 1) / bits_per_word + 1] = {0};
size_t cur_size; size_t cur_size = 0;
void sanitize_() void sanitize_()
{ {
@ -327,7 +333,7 @@ private:
template <size_t N, bool reversed> template <size_t N, bool reversed>
inline bounded_bitset<N, reversed> operator&(const bounded_bitset<N, reversed>& lhs, inline bounded_bitset<N, reversed> operator&(const bounded_bitset<N, reversed>& lhs,
const bounded_bitset<N, reversed>& rhs)noexcept const bounded_bitset<N, reversed>& rhs) noexcept
{ {
bounded_bitset<N, reversed> res(lhs); bounded_bitset<N, reversed> res(lhs);
res &= rhs; res &= rhs;
@ -357,4 +363,36 @@ inline bounded_bitset<N, reversed> fliplr(const bounded_bitset<N, reversed>& oth
} // namespace srslte } // namespace srslte
namespace fmt {
/// Custom formatter for bounded_bitset<N, reversed>
template <size_t N, bool reversed>
struct formatter<srslte::bounded_bitset<N, reversed> > {
enum { hexadecimal, binary } mode = binary;
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin())
{
auto it = ctx.begin();
while (it != ctx.end() and *it != '}') {
if (*it == 'x') {
mode = hexadecimal;
}
++it;
}
return it;
}
template <typename FormatContext>
auto format(const srslte::bounded_bitset<N, reversed>& s, FormatContext& ctx)
-> decltype(std::declval<FormatContext>().out())
{
if (mode == hexadecimal) {
return s.template to_hex(ctx.out());
}
return s.template to_string(ctx.out());
}
};
} // namespace fmt
#endif // SRSLTE_DYN_BITSET_H #endif // SRSLTE_DYN_BITSET_H

@ -36,21 +36,15 @@ public:
using iterator = T*; using iterator = T*;
using const_iterator = const T*; using const_iterator = const T*;
using size_type = std::size_t; using size_type = std::size_t;
using value_type = T;
bounded_vector() = default; bounded_vector() = default;
template <typename std::enable_if<std::is_default_constructible<T>::value, int>::type = 0> explicit bounded_vector(size_type N) { append(N); }
bounded_vector(size_type N) bounded_vector(size_type N, const T& val) { append(N, val); }
{
append(N);
}
template <typename U, typename std::enable_if<std::is_constructible<T, U>::value, int>::type = 0>
bounded_vector(size_type N, const U& init_val)
{
append(N, T(init_val));
}
bounded_vector(const bounded_vector& other) { append(other.begin(), other.end()); } bounded_vector(const bounded_vector& other) { append(other.begin(), other.end()); }
bounded_vector(bounded_vector&& other) noexcept bounded_vector(bounded_vector&& other) noexcept
{ {
static_assert(std::is_move_constructible<T>::value, "T must be move-constructible");
std::uninitialized_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), end()); std::uninitialized_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), end());
size_ = other.size(); size_ = other.size();
other.clear(); other.clear();
@ -122,19 +116,20 @@ public:
} }
T& front() { return (*this)[0]; } T& front() { return (*this)[0]; }
const T& front() const { return (*this)[0]; } const T& front() const { return (*this)[0]; }
T* data() { return reinterpret_cast<T*>(&buffer[0]); } T* data() { return &front(); }
const T* data() const { return reinterpret_cast<T*>(&buffer[0]); } const T* data() const { return &front(); }
// Iterators // Iterators
iterator begin() { return reinterpret_cast<iterator>(&buffer[0]); } iterator begin() { return data(); }
iterator end() { return begin() + size_; } iterator end() { return begin() + size_; }
const_iterator begin() const { return reinterpret_cast<const_iterator>(&buffer[0]); } const_iterator begin() const { return data(); }
const_iterator end() const { return begin() + size_; } const_iterator end() const { return begin() + size_; }
// Capacity // Capacity
bool empty() const { return size_ == 0; } bool empty() const { return size_ == 0; }
std::size_t size() const { return size_; } std::size_t size() const { return size_; }
std::size_t capacity() const { return MAX_N; } std::size_t capacity() const { return MAX_N; }
bool full() const { return size_ == MAX_N; }
// modifiers // modifiers
void clear() void clear()
@ -166,19 +161,22 @@ public:
} }
void push_back(const T& value) void push_back(const T& value)
{ {
static_assert(std::is_copy_constructible<T>::value, "T must be copy-constructible");
size_++; size_++;
assert(size_ <= MAX_N); assert(size_ <= MAX_N);
new (&back()) T(value); new (&back()) T(value);
} }
void push_back(T&& value) void push_back(T&& value)
{ {
static_assert(std::is_move_constructible<T>::value, "T must be move-constructible");
size_++; size_++;
assert(size_ <= MAX_N); assert(size_ <= MAX_N);
new (&back()) T(std::move(value)); new (&back()) T(std::move(value));
} }
template <typename... Args> template <typename... Args>
typename std::enable_if<std::is_constructible<T, Args...>::value>::type emplace_back(Args&&... args) void emplace_back(Args&&... args)
{ {
static_assert(std::is_constructible<T, Args&&...>::value, "Passed arguments to emplace_back are invalid");
size_++; size_++;
assert(size_ <= MAX_N); assert(size_ <= MAX_N);
new (&back()) T(std::forward<Args>(args)...); new (&back()) T(std::forward<Args>(args)...);
@ -189,9 +187,14 @@ public:
back().~T(); back().~T();
size_--; size_--;
} }
typename std::enable_if<std::is_default_constructible<T>::value>::type resize(size_type count) { resize(count, T()); } void resize(size_type count)
void resize(size_type count, const T& value) {
static_assert(std::is_default_constructible<T>::value, "T must be default constructible");
resize(count, T());
}
void resize(size_type count, const T& value)
{ {
static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
if (size_ > count) { if (size_ > count) {
destroy(begin() + count, end()); destroy(begin() + count, end());
size_ = count; size_ = count;
@ -222,12 +225,14 @@ private:
} }
void append(size_type N, const T& element) void append(size_type N, const T& element)
{ {
static_assert(std::is_copy_constructible<T>::value, "T must be copy-constructible");
assert(N + size_ <= MAX_N); assert(N + size_ <= MAX_N);
std::uninitialized_fill_n(end(), N, element); std::uninitialized_fill_n(end(), N, element);
size_ += N; size_ += N;
} }
void append(size_type N) void append(size_type N)
{ {
static_assert(std::is_default_constructible<T>::value, "T must be default-constructible");
assert(N + size_ <= MAX_N); assert(N + size_ <= MAX_N);
for (size_type i = size_; i < size_ + N; ++i) { for (size_type i = size_; i < size_ + N; ++i) {
new (&buffer[i]) T(); new (&buffer[i]) T();

@ -0,0 +1,450 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_CIRCULAR_BUFFER_H
#define SRSLTE_CIRCULAR_BUFFER_H
#include "srslte/adt/expected.h"
#include <array>
#include <cassert>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <type_traits>
#include <vector>
namespace srslte {
namespace detail {
template <typename T, size_t N>
size_t get_max_size(const std::array<T, N>& a)
{
return a.max_size();
}
template <typename T>
size_t get_max_size(const std::vector<T>& a)
{
return a.capacity();
}
/**
* Base common class for definition of circular buffer data structures with the following features:
* - no allocations while pushing/popping new elements. Just an internal index update
* - it provides helper methods to add/remove objects
* - it provides an iterator interface to iterate over added elements in the buffer
* - not thread-safe
* @tparam Container underlying container type used as buffer (e.g. std::array<T, N> or std::vector<T>)
*/
template <typename Container>
class base_circular_buffer
{
using T = typename Container::value_type;
public:
using value_type = T;
using difference_type = typename Container::difference_type;
struct iterator {
iterator(base_circular_buffer<Container>& parent_, size_t i) : parent(&parent_), idx(i) {}
iterator& operator++()
{
idx = (idx + 1) % parent->max_size();
return *this;
}
iterator operator++(int)
{
iterator tmp(*this);
++(*this);
return tmp;
}
iterator operator+(difference_type n)
{
iterator tmp(*this);
tmp += n;
return tmp;
}
iterator& operator+=(difference_type n)
{
idx = (idx + n) % parent->max_size();
return *this;
}
value_type* operator->() { return &parent->buffer[idx]; }
const value_type* operator->() const { return &parent->buffer[idx]; }
value_type& operator*() { return parent->buffer[idx]; }
const value_type& operator*() const { return parent->buffer[idx]; }
bool operator==(const iterator& it) const { return it.parent == parent and it.idx == idx; }
bool operator!=(const iterator& it) const { return not(*this == it); }
private:
base_circular_buffer<Container>* parent;
size_t idx;
};
template <typename... Args>
explicit base_circular_buffer(Args&&... args) : buffer(std::forward<Args>(args)...)
{}
bool try_push(T&& t)
{
if (full()) {
return false;
}
push(std::move(t));
}
void push(T&& t)
{
assert(not full());
size_t wpos = (rpos + count) % max_size();
buffer[wpos] = std::move(t);
count++;
}
bool try_push(const T& t)
{
if (full()) {
return false;
}
push(t);
}
void push(const T& t)
{
assert(not full());
size_t wpos = (rpos + count) % max_size();
buffer[wpos] = t;
count++;
}
void pop()
{
assert(not empty());
rpos = (rpos + 1) % max_size();
count--;
}
T& top()
{
assert(not empty());
return buffer[rpos];
}
const T& top() const
{
assert(not empty());
return buffer[rpos];
}
void clear() { count = 0; }
bool full() const { return count == max_size(); }
bool empty() const { return count == 0; }
size_t size() const { return count; }
size_t max_size() const { return detail::get_max_size(buffer); }
iterator begin() { return iterator(*this, rpos); }
iterator end() { return iterator(*this, (rpos + count) % max_size()); }
template <typename = std::enable_if<std::is_same<Container, std::vector<T> >::value> >
void set_size(size_t size)
{
buffer.resize(size);
}
private:
Container buffer;
size_t rpos = 0;
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
* - provides blocking and non-blocking push/pop APIs
* - thread-safe
* @tparam CircBuffer underlying circular buffer data type (e.g. static_circular_buffer<T, N> or dyn_circular_buffer<T>)
* @tparam PushingFunc function void(const T&) called while pushing an element to the queue
* @tparam PoppingFunc function void(const T&) called while popping an element from the queue
*/
template <typename CircBuffer, typename PushingFunc, typename PoppingFunc>
class base_blocking_queue
{
using T = typename CircBuffer::value_type;
public:
template <typename... Args>
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_)
{}
void stop()
{
std::unique_lock<std::mutex> lock(mutex);
if (active) {
active = false;
if (nof_waiting == 0) {
return;
}
do {
lock.unlock();
cvar_empty.notify_all();
cvar_full.notify_all();
std::this_thread::yield();
lock.lock();
} while (nof_waiting > 0);
}
}
bool try_push(const T& t) { return push_(t, false); }
srslte::error_type<T> try_push(T&& t) { return push_(std::move(t), false); }
bool push_blocking(const T& t) { return push_(t, true); }
srslte::error_type<T> push_blocking(T&& t) { return push_(std::move(t), true); }
bool try_pop(T& obj) { return pop_(obj, false); }
T pop_blocking()
{
T obj{};
pop_(obj, true);
return obj;
}
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)) {
}
}
size_t size() const
{
std::lock_guard<std::mutex> lock(mutex);
return circ_buffer.size();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(mutex);
return circ_buffer.empty();
}
bool full() const
{
std::lock_guard<std::mutex> lock(mutex);
return circ_buffer.full();
}
size_t max_size() const
{
std::lock_guard<std::mutex> lock(mutex);
return circ_buffer.max_size();
}
bool is_stopped() const
{
std::lock_guard<std::mutex> lock(mutex);
return not active;
}
template <typename F>
bool try_call_on_front(F&& f)
{
std::lock_guard<std::mutex> lock(mutex);
if (not circ_buffer.empty()) {
f(circ_buffer.top());
return true;
}
return false;
}
protected:
bool active = true;
uint8_t nof_waiting = 0;
mutable std::mutex mutex;
std::condition_variable cvar_empty, cvar_full;
PushingFunc push_func;
PoppingFunc pop_func;
CircBuffer circ_buffer;
~base_blocking_queue() { stop(); }
bool push_(const T& t, bool block_mode)
{
std::unique_lock<std::mutex> lock(mutex);
if (not active) {
return false;
}
if (circ_buffer.full()) {
if (not block_mode) {
return false;
}
nof_waiting++;
while (circ_buffer.full() and active) {
cvar_full.wait(lock);
}
nof_waiting--;
if (not active) {
return false;
}
}
push_func(t);
circ_buffer.push(t);
lock.unlock();
cvar_empty.notify_one();
return true;
}
srslte::error_type<T> push_(T&& t, bool block_mode)
{
std::unique_lock<std::mutex> lock(mutex);
if (not active) {
return std::move(t);
}
if (circ_buffer.full()) {
if (not block_mode) {
return std::move(t);
}
nof_waiting++;
while (circ_buffer.full() and active) {
cvar_full.wait(lock);
}
nof_waiting--;
if (not active) {
return std::move(t);
}
}
push_func(t);
circ_buffer.push(std::move(t));
lock.unlock();
cvar_empty.notify_one();
return {};
}
bool pop_(T& obj, bool block, const std::chrono::system_clock::time_point* until = nullptr)
{
std::unique_lock<std::mutex> lock(mutex);
if (not active) {
return false;
}
if (circ_buffer.empty()) {
if (not block) {
return false;
}
nof_waiting++;
if (until == nullptr) {
cvar_empty.wait(lock, [this]() { return not circ_buffer.empty() or not active; });
} else {
cvar_empty.wait_until(lock, *until, [this]() { return not circ_buffer.empty() or not active; });
}
nof_waiting--;
if (circ_buffer.empty()) {
// either queue got deactivated or there was a timeout
return false;
}
}
obj = std::move(circ_buffer.top());
pop_func(obj);
circ_buffer.pop();
lock.unlock();
cvar_full.notify_one();
return true;
}
};
} // namespace detail
/**
* Circular buffer with fixed, embedded buffer storage via a std::array<T, N>.
* - Single allocation at object creation for std::array. Given that the buffer size is known at compile-time, the
* circular iteration over the buffer may be more optimized (e.g. when N is a power of 2, % operator can be avoided)
* - not thread-safe
* @tparam T value type stored by buffer
* @tparam N size of the queue
*/
template <typename T, size_t N>
class static_circular_buffer : public detail::base_circular_buffer<std::array<T, N> >
{};
/**
* Circular buffer with buffer storage via a std::vector<T>.
* - size can be defined at run-time.
* - not thread-safe
* @tparam T value type stored by buffer
*/
template <typename T>
class dyn_circular_buffer : public detail::base_circular_buffer<std::vector<T> >
{
using base_t = detail::base_circular_buffer<std::vector<T> >;
public:
dyn_circular_buffer() = default;
explicit dyn_circular_buffer(size_t size) : base_t(size) {}
void set_size(size_t size)
{
// Note: dynamic resizes not supported.
assert(base_t::empty());
base_t::set_size(size);
}
};
/**
* Blocking queue with fixed, embedded buffer storage via a std::array<T, N>.
* - Blocking push/pop API via push_blocking(...) and pop_blocking(...) methods
* - Non-blocking push/pop API via try_push(...) and try_pop(...) methods
* - Only one initial allocation for the std::array<T, N>
* - thread-safe
* @tparam T value type stored by buffer
* @tparam N size of queue
* @tparam PushingCallback function void(const T&) called while pushing an element to the queue
* @tparam PoppingCallback function void(const T&) called while popping an element from the queue
*/
template <typename T,
size_t N,
typename PushingCallback = detail::noop_operator,
typename PoppingCallback = detail::noop_operator>
class static_blocking_queue
: public detail::base_blocking_queue<static_circular_buffer<T, N>, PushingCallback, PoppingCallback>
{
using base_t = detail::base_blocking_queue<static_circular_buffer<T, N>, PushingCallback, PoppingCallback>;
public:
explicit static_blocking_queue(PushingCallback push_callback = {}, PoppingCallback pop_callback = {}) :
base_t(push_callback, pop_callback)
{}
};
/**
* Blocking queue with buffer storage represented via a std::vector<T>. Features:
* - Blocking push/pop API via push_blocking(...) and pop_blocking(...) methods
* - Non-blocking push/pop API via try_push(...) and try_pop(...) methods
* - Size can be defined at runtime.
* - thread-safe
* @tparam T value type stored by buffer
* @tparam PushingCallback function void(const T&) called while pushing an element to the queue
* @tparam PoppingCallback function void(const T&) called while popping an element from the queue
*/
template <typename T,
typename PushingCallback = detail::noop_operator,
typename PoppingCallback = detail::noop_operator>
class dyn_blocking_queue : public detail::base_blocking_queue<dyn_circular_buffer<T>, PushingCallback, PoppingCallback>
{
using base_t = detail::base_blocking_queue<dyn_circular_buffer<T>, PushingCallback, PoppingCallback>;
public:
dyn_blocking_queue() = default;
explicit dyn_blocking_queue(size_t size, PushingCallback push_callback = {}, PoppingCallback pop_callback = {}) :
base_t(push_callback, pop_callback, size)
{}
void set_size(size_t size) { base_t::circ_buffer.set_size(size); }
};
} // namespace srslte
#endif // SRSLTE_CIRCULAR_BUFFER_H

@ -86,8 +86,6 @@ public:
bool contains(T point) const { return start_ <= point and point < stop_; } bool contains(T point) const { return start_ <= point and point < stop_; }
std::string to_string() const { return fmt::format("[{},{})", start_, stop_); }
private: private:
T start_; T start_;
T stop_; T stop_;
@ -143,13 +141,19 @@ interval<T> make_intersection(const interval<T>& lhs, const interval<T>& rhs)
return lhs & rhs; return lhs & rhs;
} }
} // namespace srslte
namespace fmt {
template <typename T> template <typename T>
std::ostream& operator<<(std::ostream& out, const interval<T>& interv) struct formatter<srslte::interval<T> > : public formatter<T> {
{ template <typename FormatContext>
out << interv.to_string(); auto format(const srslte::interval<T>& interv, FormatContext& ctx) -> decltype(std::declval<FormatContext>().out())
return out; {
} return format_to(ctx.out(), "[{}, {})", interv.start(), interv.stop());
}
};
} // namespace srslte } // namespace fmt
#endif // SRSLTE_INTERVAL_H #endif // SRSLTE_INTERVAL_H

@ -22,6 +22,7 @@
#ifndef SRSLTE_MEM_POOL_H #ifndef SRSLTE_MEM_POOL_H
#define SRSLTE_MEM_POOL_H #define SRSLTE_MEM_POOL_H
#include "srslte/common/thread_pool.h"
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
@ -205,6 +206,97 @@ public:
} }
}; };
/**
* Pool specialized for in allocating batches of objects in a preemptive way in a background thread to minimize latency.
* Note: Current implementation assumes that the pool object will outlive the background callbacks to allocate new
* batches
* @tparam T individual object type that is being allocated
* @tparam BatchSize number of T objects in a batch
* @tparam ThresholdSize number of T objects below which a new batch needs to be allocated
*/
template <typename T, size_t BatchSize, size_t ThresholdSize>
class background_allocator_obj_pool
{
static_assert(ThresholdSize > 0, "ThresholdSize needs to be positive");
static_assert(BatchSize > 1, "BatchSize needs to be higher than 1");
public:
background_allocator_obj_pool(bool lazy_start = false)
{
if (not lazy_start) {
allocate_batch_in_background();
}
}
background_allocator_obj_pool(background_allocator_obj_pool&&) = delete;
background_allocator_obj_pool(const background_allocator_obj_pool&) = delete;
background_allocator_obj_pool& operator=(background_allocator_obj_pool&&) = delete;
background_allocator_obj_pool& operator=(const background_allocator_obj_pool&) = delete;
~background_allocator_obj_pool()
{
std::lock_guard<std::mutex> lock(mutex);
batches.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)
{
assert(sz == sizeof(T));
std::lock_guard<std::mutex> lock(mutex);
uint8_t* block = obj_cache.try_pop();
if (block != nullptr) {
// allocation successful
if (obj_cache.size() < ThresholdSize) {
get_background_workers().push_task([this]() {
std::lock_guard<std::mutex> lock(mutex);
allocate_batch_();
});
}
return block;
}
// try allocation of new batch in same thread as caller.
allocate_batch_();
return obj_cache.try_pop();
}
void deallocate_node(void* p)
{
std::lock_guard<std::mutex> lock(mutex);
assert(p != nullptr);
if (p != nullptr) {
obj_cache.push(static_cast<uint8_t*>(p));
}
}
void allocate_batch_in_background()
{
get_background_workers().push_task([this]() {
std::lock_guard<std::mutex> lock(mutex);
allocate_batch_();
});
}
private:
using obj_storage_t = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
using batch_obj_t = std::array<obj_storage_t, BatchSize>;
/// Unprotected allocation of new Batch of Objects
void allocate_batch_()
{
batches.emplace_back(new batch_obj_t());
batch_obj_t& batch = *batches.back();
for (obj_storage_t& obj_store : batch) {
obj_cache.push(reinterpret_cast<uint8_t*>(&obj_store));
}
}
// memory stack to cache allocate memory chunks
std::mutex mutex;
memblock_stack obj_cache;
std::vector<std::unique_ptr<batch_obj_t> > batches;
};
} // namespace srslte } // namespace srslte
#endif // SRSLTE_MEM_POOL_H #endif // SRSLTE_MEM_POOL_H

@ -181,7 +181,7 @@ public:
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_empty() const { return oper_ptr == &empty_table; }
bool is_in_small_buffer() const { return oper_ptr->is_in_small_buffer(); } bool is_in_small_buffer() const { return oper_ptr->is_in_small_buffer(); }
private: private:

@ -35,7 +35,6 @@
*******************************************************************************/ *******************************************************************************/
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/srslog/srslog.h" #include "srslte/srslog/srslog.h"
namespace srslte { namespace srslte {
@ -60,6 +59,7 @@ public:
if (capacity_ > 0) { if (capacity_ > 0) {
nof_buffers = (uint32_t)capacity_; nof_buffers = (uint32_t)capacity_;
} }
used.reserve(nof_buffers);
pthread_mutex_init(&mutex, nullptr); pthread_mutex_init(&mutex, nullptr);
pthread_cond_init(&cv_not_empty, nullptr); pthread_cond_init(&cv_not_empty, nullptr);
for (uint32_t i = 0; i < nof_buffers; i++) { for (uint32_t i = 0; i < nof_buffers; i++) {

@ -1,159 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: log.h
*
* Description: Abstract logging service
*
* Reference:
*****************************************************************************/
#ifndef SRSLTE_LOG_H
#define SRSLTE_LOG_H
#include "srslte/common/standard_streams.h"
#include <algorithm>
#include <stdint.h>
#include <string>
namespace srslte {
typedef enum {
LOG_LEVEL_NONE = 0,
LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG,
LOG_LEVEL_N_ITEMS
} LOG_LEVEL_ENUM;
static const char log_level_text[LOG_LEVEL_N_ITEMS][16] = {"None ", "Error ", "Warning", "Info ", "Debug "};
static const char log_level_text_short[LOG_LEVEL_N_ITEMS][16] = {"[-]", "[E]", "[W]", "[I]", "[D]"};
class log
{
public:
log()
{
service_name = "";
tti = 0;
level = LOG_LEVEL_NONE;
hex_limit = 0;
add_string_en = false;
}
explicit log(std::string service_name_)
{
service_name = std::move(service_name_);
tti = 0;
level = LOG_LEVEL_NONE;
hex_limit = 0;
add_string_en = false;
}
log(const log&) = delete;
log& operator=(const log&) = delete;
virtual ~log() = default;
// This function shall be called at the start of every tti for printing tti
void step(uint32_t tti_)
{
tti = tti_;
add_string_en = false;
}
void prepend_string(std::string s)
{
add_string_en = true;
add_string_val = std::move(s);
}
uint32_t get_tti() { return tti; }
void set_level(LOG_LEVEL_ENUM l) { level = l; }
void set_level(std::string l) { set_level(get_level_from_string(std::move(l))); }
static srslte::LOG_LEVEL_ENUM get_level_from_string(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if ("NONE" == l) {
return srslte::LOG_LEVEL_NONE;
} else if ("ERROR" == l) {
return srslte::LOG_LEVEL_ERROR;
} else if ("WARNING" == l) {
return srslte::LOG_LEVEL_WARNING;
} else if ("INFO" == l) {
return srslte::LOG_LEVEL_INFO;
} else if ("DEBUG" == l) {
return srslte::LOG_LEVEL_DEBUG;
} else {
return srslte::LOG_LEVEL_NONE;
}
}
LOG_LEVEL_ENUM get_level() { return level; }
const std::string& get_service_name() const { return service_name; }
void set_hex_limit(int limit) { hex_limit = limit; }
int get_hex_limit() { return hex_limit; }
// Pure virtual methods for logging
virtual void error(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
virtual void warning(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
virtual void info(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
virtual void info_long(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
virtual void debug(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
virtual void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
// Same with hex dump
virtual void error_hex(const uint8_t*, int, const char*, ...) __attribute__((format(printf, 4, 5)))
{
error("error_hex not implemented.\n");
}
virtual void warning_hex(const uint8_t*, int, const char*, ...) __attribute__((format(printf, 4, 5)))
{
error("warning_hex not implemented.\n");
}
virtual void info_hex(const uint8_t*, int, const char*, ...) __attribute__((format(printf, 4, 5)))
{
error("info_hex not implemented.\n");
}
virtual void debug_hex(const uint8_t*, int, const char*, ...) __attribute__((format(printf, 4, 5)))
{
error("debug_hex not implemented.\n");
}
protected:
uint32_t tti;
LOG_LEVEL_ENUM level;
int hex_limit;
bool add_string_en;
std::string add_string_val;
std::string service_name;
};
} // namespace srslte
#endif // SRSLTE_LOG_H

@ -1,99 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: log_filter.h
* Description: Log filter for a specific layer or element.
* Performs filtering based on log level, generates
* timestamped log strings and passes them to the
* common logger object.
*****************************************************************************/
#ifndef SRSLTE_LOG_FILTER_H
#define SRSLTE_LOG_FILTER_H
#include <stdarg.h>
#include <string>
#include "srslte/common/log.h"
#include "srslte/common/logger.h"
#include "srslte/common/logger_srslog_wrapper.h"
#include "srslte/phy/common/timestamp.h"
namespace srslte {
typedef std::string* str_ptr;
class log_filter : public srslte::log
{
public:
log_filter();
log_filter(std::string layer);
log_filter(std::string layer, logger* logger_, bool tti = false);
void init(std::string layer, logger* logger_, bool tti = false);
void error(const char* message, ...) __attribute__((format(printf, 2, 3)));
void warning(const char* message, ...) __attribute__((format(printf, 2, 3)));
void info(const char* message, ...) __attribute__((format(printf, 2, 3)));
void info_long(const char* message, ...) __attribute__((format(printf, 2, 3)));
void debug(const char* message, ...) __attribute__((format(printf, 2, 3)));
void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3)));
void error_hex(const uint8_t* hex, int size, const char* message, ...) __attribute__((format(printf, 4, 5)));
void warning_hex(const uint8_t* hex, int size, const char* message, ...) __attribute__((format(printf, 4, 5)));
void info_hex(const uint8_t* hex, int size, const char* message, ...) __attribute__((format(printf, 4, 5)));
void debug_hex(const uint8_t* hex, int size, const char* message, ...) __attribute__((format(printf, 4, 5)));
class time_itf
{
public:
virtual srslte_timestamp_t get_time() = 0;
};
typedef enum { TIME, EPOCH } time_format_t;
void set_time_src(time_itf* source, time_format_t format);
protected:
std::unique_ptr<logger> default_logger;
logger* logger_h;
bool do_tti;
static const int char_buff_size = logger::preallocated_log_str_size - 64 * 3;
time_itf* time_src;
time_format_t time_format;
void all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
char* msg,
const uint8_t* hex = nullptr,
int size = 0,
bool long_msg = false);
void now_time(char* buffer, const uint32_t buffer_len);
void get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len);
std::string hex_string(const uint8_t* hex, int size);
};
} // namespace srslte
#endif // SRSLTE_LOG_FILTER_H

@ -30,37 +30,11 @@
namespace srslte { namespace srslte {
#define Error(fmt, ...) \ #define Error(fmt, ...) logger.error(fmt, ##__VA_ARGS__)
do { \ #define Warning(fmt, ...) logger.warning(fmt, ##__VA_ARGS__)
if (log_h.get() != nullptr) { \ #define Info(fmt, ...) logger.info(fmt, ##__VA_ARGS__)
log_h->error(fmt, ##__VA_ARGS__); \ #define Debug(fmt, ...) logger.debug(fmt, ##__VA_ARGS__)
} \ #define Console(fmt, ...) srslte::console(fmt, ##__VA_ARGS__)
} while (0)
#define Warning(fmt, ...) \
do { \
if (log_h.get() != nullptr) { \
log_h->warning(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define Info(fmt, ...) \
do { \
if (log_h.get() != nullptr) { \
log_h->info(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define Debug(fmt, ...) \
do { \
if (log_h.get() != nullptr) { \
log_h->debug(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define Console(fmt, ...) \
do { \
if (log_h.get() != nullptr) { \
srslte::console(fmt, ##__VA_ARGS__); \
} \
} while (0)
} // namespace srslte } // namespace srslte

@ -1,112 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: logger.h
* Description: Interface for logging output
*****************************************************************************/
#ifndef SRSLTE_LOGGER_H
#define SRSLTE_LOGGER_H
#include "buffer_pool.h"
#include <memory>
#include <stdio.h>
#include <string>
namespace srslte {
class logger
{
public:
const static uint32_t preallocated_log_str_size = 1024;
logger() : pool(16 * 1024) {}
virtual ~logger() = default;
class log_str
{
public:
log_str(const char* msg_ = nullptr, uint32_t size_ = 0)
{
size = size_ ? size_ : preallocated_log_str_size;
msg = new char[size];
if (msg_) {
strncpy(msg, msg_, size);
} else {
msg[0] = '\0';
}
}
log_str(const log_str&) = delete;
log_str& operator=(const log_str&) = delete;
~log_str() { delete[] msg; }
void reset() { msg[0] = '\0'; }
char* str() { return msg; }
uint32_t get_buffer_size() { return size; }
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN] = {};
#endif
private:
uint32_t size;
char* msg;
};
typedef buffer_pool<log_str> log_str_pool_t;
class log_str_deleter
{
public:
explicit log_str_deleter(log_str_pool_t* pool_ = nullptr) : pool(pool_) {}
void operator()(log_str* buf)
{
if (buf) {
if (pool) {
buf->reset();
pool->deallocate(buf);
} else {
delete buf;
}
}
}
private:
log_str_pool_t* pool;
};
typedef std::unique_ptr<log_str, log_str_deleter> unique_log_str_t;
void log_char(const char* msg) { log(unique_log_str_t(new log_str(msg), log_str_deleter())); }
virtual void log(unique_log_str_t msg) = 0;
log_str_pool_t& get_pool() { return pool; }
unique_log_str_t allocate_unique_log_str()
{
return unique_log_str_t(pool.allocate(), logger::log_str_deleter(&pool));
}
private:
log_str_pool_t pool;
};
} // namespace srslte
#endif // SRSLTE_LOGGER_H

@ -1,49 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_LOGGER_SRSLOG_WRAPPER_H
#define SRSLTE_LOGGER_SRSLOG_WRAPPER_H
#include "srslte/common/logger.h"
namespace srslog {
class log_channel;
} // namespace srslog
namespace srslte {
/// This logger implementation uses the srsLog framework to write log entries.
class srslog_wrapper : public logger
{
public:
explicit srslog_wrapper(srslog::log_channel& chan) : chan(chan) {}
void log(unique_log_str_t msg) override;
private:
srslog::log_channel& chan;
};
} // namespace srslte
#endif // SRSLTE_LOGGER_SRSLOG_WRAPPER_H

@ -1,103 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_LOGMAP_H
#define SRSLTE_LOGMAP_H
#include "srslte/common/log.h"
#include "srslte/common/logger.h"
#include "srslte/common/logger_srslog_wrapper.h"
#include "srslte/common/singleton.h"
#include <memory>
#include <mutex>
#include <unordered_map>
namespace srslte {
class log_ref
{
using ptr_type = std::unique_ptr<log>*;
public:
log_ref() = default;
explicit log_ref(ptr_type p) : ptr_(p) {}
explicit log_ref(const char* name);
// works like a log*
log* operator->() { return ptr_->get(); }
log* operator->() const { return ptr_->get(); }
// in case we want to obtain log*
log* operator*() { return ptr_->get(); }
log* get() { return ptr_->get(); }
// identity defined by ref address
bool operator==(const log_ref& l) { return ptr_ == l.ptr_; }
// to do checks like if(log_ref)
operator bool() { return ptr_ != nullptr; }
private:
ptr_type ptr_ = nullptr;
};
class logmap : public singleton_t<logmap>
{
public:
// Access to log map by servicename. If servicename does not exist, create a new log_filter with default cfg
// Access to the map is protected by a mutex
static log_ref get(std::string servicename);
// register manually created log
static void register_log(std::unique_ptr<log> log_ptr);
static std::unique_ptr<srslte::log> deregister_log(const std::string& servicename);
// set default logger
static void set_default_logger(logger* logger_);
// set default log level
static void set_default_log_level(LOG_LEVEL_ENUM l);
// set default hex limit
static void set_default_hex_limit(int hex_limit);
protected:
logmap();
private:
log_ref get_impl(std::string servicename);
// default cfg
std::unique_ptr<srslog_wrapper> stdout_channel;
logger* default_logger = nullptr;
srslte::LOG_LEVEL_ENUM default_log_level = LOG_LEVEL_WARNING;
int default_hex_limit = 1024;
// state
std::mutex mutex;
std::unordered_map<std::string, std::unique_ptr<log> > log_map;
};
} // namespace srslte
#endif // SRSLTE_LOGMAP_H

@ -22,7 +22,7 @@
#ifndef SRSLTE_MAC_PCAP_BASE_H #ifndef SRSLTE_MAC_PCAP_BASE_H
#define SRSLTE_MAC_PCAP_BASE_H #define SRSLTE_MAC_PCAP_BASE_H
#include "srslte/common/block_queue.h" #include "srslte/adt/circular_buffer.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/pcap.h" #include "srslte/common/pcap.h"
@ -102,11 +102,11 @@ protected:
virtual void write_pdu(pcap_pdu_t& pdu) = 0; virtual void write_pdu(pcap_pdu_t& pdu) = 0;
void run_thread() final; void run_thread() final;
std::mutex mutex; std::mutex mutex;
srslog::basic_logger& logger; srslog::basic_logger& logger;
bool running = false; bool running = false;
block_queue<pcap_pdu_t> queue; static_blocking_queue<pcap_pdu_t, 256> queue;
uint16_t ue_id = 0; uint16_t ue_id = 0;
private: private:
void pack_and_queue(uint8_t* payload, void pack_and_queue(uint8_t* payload,

@ -27,7 +27,6 @@
#ifndef SRSLTE_NETSOURE_HANDLER_H #ifndef SRSLTE_NETSOURE_HANDLER_H
#define SRSLTE_NETSOURE_HANDLER_H #define SRSLTE_NETSOURE_HANDLER_H
#include "srslte/common/log.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/phy/io/netsource.h" #include "srslte/phy/io/netsource.h"
#include <array> #include <array>
@ -70,8 +69,6 @@ public:
unique_byte_array_t rx_buf; unique_byte_array_t rx_buf;
srslte_netsource_t net_source; srslte_netsource_t net_source;
srslte::log* log = nullptr;
}; };
#endif // SRSLTE_NETSOURE_HANDLER_H #endif // SRSLTE_NETSOURE_HANDLER_H

@ -22,6 +22,7 @@
#ifndef SRSLTE_STRING_HELPERS_H #ifndef SRSLTE_STRING_HELPERS_H
#define SRSLTE_STRING_HELPERS_H #define SRSLTE_STRING_HELPERS_H
#include "srslte/srslog/bundled/fmt/format.h"
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
#include <string> #include <string>
@ -120,6 +121,13 @@ static inline void string_parse_list(const std::string& input, char delimiter, I
} }
} }
template <size_t N>
const char* to_c_str(fmt::basic_memory_buffer<char, N>& mem_buffer)
{
mem_buffer.push_back('\0');
return mem_buffer.data();
}
} // namespace srslte } // namespace srslte
#endif // SRSLTE_STRING_HELPERS_H #endif // SRSLTE_STRING_HELPERS_H

@ -26,73 +26,13 @@
#ifdef __cplusplus #ifdef __cplusplus
#include "srslte/common/log.h" #include "srslte/common/standard_streams.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/logmap.h"
#include "srslte/srslog/srslog.h" #include "srslte/srslog/srslog.h"
#include <atomic> #include <atomic>
#include <cstdio> #include <cstdio>
namespace srslte { namespace srslte {
// Description: log filter that we can instantiate in a specific test scope, and cleans itself on scope exit
// useful if we want to define specific logging policies within a scope (e.g. null logger, count number of errors,
// exit on error, log special diagnostics on destruction). It restores the previous logger after exiting the scope
class test_log_filter : public srslte::log_filter
{
public:
explicit test_log_filter(std::string layer) : srslte::log_filter(std::move(layer))
{
set_level(srslte::LOG_LEVEL_DEBUG);
}
test_log_filter(const test_log_filter&) = delete;
test_log_filter(test_log_filter&&) = delete;
test_log_filter& operator=(const test_log_filter&) = delete;
test_log_filter& operator=(test_log_filter&&) = delete;
~test_log_filter() override = default;
void error(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
error_counter++;
if (level >= srslte::LOG_LEVEL_ERROR) {
char args_msg[char_buff_size];
va_list args;
va_start(args, message);
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) {
all_log(srslte::LOG_LEVEL_ERROR, tti, args_msg);
}
va_end(args);
}
if (exit_on_error) {
exit(-1);
}
}
void warning(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
warn_counter++;
if (level >= srslte::LOG_LEVEL_WARNING) {
char args_msg[char_buff_size];
va_list args;
va_start(args, message);
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) {
all_log(srslte::LOG_LEVEL_WARNING, tti, args_msg);
}
va_end(args);
}
}
virtual void log_diagnostics()
{
if (error_counter > 0 or warn_counter > 0) {
info("STATUS: counted %d errors and %d warnings.\n", error_counter, warn_counter);
}
}
bool exit_on_error = false;
uint32_t error_counter = 0, warn_counter = 0;
};
/// This custom sink intercepts log messages to count error and warning log entries. /// This custom sink intercepts log messages to count error and warning log entries.
class log_sink_spy : public srslog::sink class log_sink_spy : public srslog::sink
{ {
@ -197,106 +137,17 @@ private:
std::vector<std::string> entries; std::vector<std::string> entries;
}; };
// specialization of test_log_filter to store last logged message
class nullsink_log : public test_log_filter
{
public:
explicit nullsink_log(std::string layer) : test_log_filter(std::move(layer)) {}
void debug(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
va_list args;
va_start(args, message);
log_va_list(LOG_LEVEL_DEBUG, message, args);
va_end(args);
}
void info(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
va_list args;
va_start(args, message);
log_va_list(LOG_LEVEL_INFO, message, args);
va_end(args);
}
void warning(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
warn_counter++;
va_list args;
va_start(args, message);
log_va_list(LOG_LEVEL_WARNING, message, args);
va_end(args);
}
void error(const char* message, ...) override __attribute__((format(printf, 2, 3)))
{
error_counter++;
va_list args;
va_start(args, message);
log_va_list(LOG_LEVEL_ERROR, message, args);
va_end(args);
if (exit_on_error) {
exit(-1);
}
}
srslte::LOG_LEVEL_ENUM last_log_level = LOG_LEVEL_NONE;
std::string last_log_msg;
private:
void log_va_list(srslte::LOG_LEVEL_ENUM loglevel, const char* message, va_list argp)
{
last_log_level = loglevel;
if (level >= loglevel) {
char args_msg[char_buff_size];
if (vsnprintf(args_msg, char_buff_size, message, argp) > 0) {
last_log_msg = args_msg;
}
}
}
};
template <typename Log>
class scoped_log
{
public:
template <typename... Args>
explicit scoped_log(Args&&... args)
{
std::unique_ptr<Log> l{new Log{std::forward<Args>(args)...}};
// store previous log, and register the newly created one
prev_log = srslte::logmap::deregister_log(l->get_service_name());
current_log = l.get();
srslte::logmap::register_log(std::move(l));
}
scoped_log(scoped_log<Log>&&) noexcept = default;
~scoped_log()
{
srslte::logmap::deregister_log(current_log->get_service_name());
if (prev_log != nullptr) {
srslte::logmap::register_log(std::move(prev_log));
}
}
Log* operator->() { return current_log; }
Log* get() { return current_log; }
private:
Log* current_log = nullptr;
std::unique_ptr<srslte::log> prev_log;
};
} // namespace srslte } // namespace srslte
#define TESTERROR(fmt, ...) \ #define TESTERROR(fmt, ...) \
do { \ do { \
srslte::logmap::get("TEST")->error(fmt, ##__VA_ARGS__); \ srslog::fetch_basic_logger("TEST").error(fmt, ##__VA_ARGS__); \
return SRSLTE_ERROR; \ return SRSLTE_ERROR; \
} while (0) } while (0)
#define TESTWARN(fmt, ...) \ #define TESTWARN(fmt, ...) \
do { \ do { \
srslte::logmap::get("TEST")->warning(fmt, ##__VA_ARGS__); \ srslog::fetch_basic_logger("TEST").warning(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define CONDERROR(cond, fmt, ...) \ #define CONDERROR(cond, fmt, ...) \

@ -29,6 +29,7 @@
#ifndef SRSLTE_TIMERS_H #ifndef SRSLTE_TIMERS_H
#define SRSLTE_TIMERS_H #define SRSLTE_TIMERS_H
#include "srslte/adt/move_callback.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
@ -54,11 +55,11 @@ class timer_handler
constexpr static uint32_t MAX_TIMER_VALUE = std::numeric_limits<uint32_t>::max() / 2; constexpr static uint32_t MAX_TIMER_VALUE = std::numeric_limits<uint32_t>::max() / 2;
struct timer_impl { struct timer_impl {
timer_handler* parent; timer_handler* parent;
uint32_t duration = 0, timeout = 0; uint32_t duration = 0, timeout = 0;
bool running = false; bool running = false;
bool active = false; bool active = false;
std::function<void(uint32_t)> callback; srslte::move_callback<void(uint32_t)> callback;
explicit timer_impl(timer_handler* parent_) : parent(parent_) {} explicit timer_impl(timer_handler* parent_) : parent(parent_) {}
@ -88,7 +89,7 @@ class timer_handler
return true; return true;
} }
bool set(uint32_t duration_, std::function<void(int)> callback_) bool set(uint32_t duration_, srslte::move_callback<void(uint32_t)> callback_)
{ {
if (set(duration_)) { if (set(duration_)) {
callback = std::move(callback_); callback = std::move(callback_);
@ -122,7 +123,7 @@ class timer_handler
stop(); stop();
duration = 0; duration = 0;
active = false; active = false;
callback = std::function<void(uint32_t)>(); callback = srslte::move_callback<void(uint32_t)>();
// leave run_id unchanged. Since the timeout was changed, we shall not get spurious triggering // leave run_id unchanged. Since the timeout was changed, we shall not get spurious triggering
} }
@ -130,7 +131,7 @@ class timer_handler
{ {
if (is_running()) { if (is_running()) {
running = false; running = false;
if (callback) { if (not callback.is_empty()) {
callback(id()); callback(id());
} }
} }
@ -173,7 +174,10 @@ public:
bool is_valid() const { return parent != nullptr; } bool is_valid() const { return parent != nullptr; }
void set(uint32_t duration_, const std::function<void(int)>& callback_) { impl()->set(duration_, callback_); } void set(uint32_t duration_, move_callback<void(uint32_t)> callback_)
{
impl()->set(duration_, std::move(callback_));
}
void set(uint32_t duration_) { impl()->set(duration_); } void set(uint32_t duration_) { impl()->set(duration_); }
@ -279,8 +283,8 @@ public:
template <typename F> template <typename F>
void defer_callback(uint32_t duration, const F& func) void defer_callback(uint32_t duration, const F& func)
{ {
uint32_t id = alloc_timer(); uint32_t id = alloc_timer();
std::function<void(uint32_t)> c = [func, this, id](uint32_t tid) { srslte::move_callback<void(uint32_t)> c = [func, this, id](uint32_t tid) {
func(); func();
// auto-deletes timer // auto-deletes timer
timer_list[id].clear(); timer_list[id].clear();

@ -22,6 +22,8 @@
#ifndef SRSLTE_ENB_GTPU_INTERFACES_H #ifndef SRSLTE_ENB_GTPU_INTERFACES_H
#define SRSLTE_ENB_GTPU_INTERFACES_H #define SRSLTE_ENB_GTPU_INTERFACES_H
#include "srslte/common/byte_buffer.h"
namespace srsenb { namespace srsenb {
// GTPU interface for PDCP // GTPU interface for PDCP

@ -62,8 +62,8 @@ class pdcp_interface_rlc
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) = 0; virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sns) = 0;
virtual void notify_failure(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& pdcp_sns) = 0; virtual void notify_failure(uint16_t rnti, uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sns) = 0;
}; };
} // namespace srsenb } // namespace srsenb

@ -92,8 +92,8 @@ class pdcp_interface_rlc_nr
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& tx_count) = 0; virtual void notify_delivery(uint16_t rnti, uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sns) = 0;
virtual void notify_failure(uint16_t rnti, uint32_t lcid, const std::vector<uint32_t>& tx_count) = 0; virtual void notify_failure(uint16_t rnti, uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sns) = 0;
}; };
class pdcp_interface_rrc_nr class pdcp_interface_rrc_nr

@ -27,6 +27,7 @@
#ifndef SRSLTE_PDCP_INTERFACE_TYPES_H #ifndef SRSLTE_PDCP_INTERFACE_TYPES_H
#define SRSLTE_PDCP_INTERFACE_TYPES_H #define SRSLTE_PDCP_INTERFACE_TYPES_H
#include "srslte/adt/bounded_vector.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include <math.h> #include <math.h>
#include <stdint.h> #include <stdint.h>
@ -177,6 +178,11 @@ struct pdcp_lte_state_t {
uint32_t reordering_pdcp_rx_count; uint32_t reordering_pdcp_rx_count;
}; };
// Custom type for interface between PDCP and RLC to convey SDU delivery status
#define MAX_SDUS_PER_RLC_PDU (256) // default to RLC SDU queue length
#define MAX_SDUS_TO_NOTIFY (MAX_SDUS_PER_RLC_PDU) // Arbitrarily chosen limit
typedef srslte::bounded_vector<uint32_t, MAX_SDUS_TO_NOTIFY> pdcp_sn_vector_t;
} // namespace srslte } // namespace srslte
#endif // SRSLTE_PDCP_INTERFACE_TYPES_H #endif // SRSLTE_PDCP_INTERFACE_TYPES_H

@ -23,6 +23,7 @@
#define SRSLTE_UE_GW_INTERFACES_H #define SRSLTE_UE_GW_INTERFACES_H
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "srslte/common/byte_buffer.h"
namespace srsue { namespace srsue {

@ -23,6 +23,7 @@
#define SRSLTE_UE_PDCP_INTERFACES_H #define SRSLTE_UE_PDCP_INTERFACES_H
#include "pdcp_interface_types.h" #include "pdcp_interface_types.h"
#include "srslte/common/byte_buffer.h"
namespace srsue { namespace srsue {
@ -48,13 +49,13 @@ class pdcp_interface_rlc
{ {
public: public:
/* RLC calls PDCP to push a PDCP PDU. */ /* RLC calls PDCP to push a PDCP PDU. */
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0; virtual void notify_delivery(uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sn) = 0;
virtual void notify_failure(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) = 0; virtual void notify_failure(uint32_t lcid, const srslte::pdcp_sn_vector_t& pdcp_sn) = 0;
}; };
class pdcp_interface_gw class pdcp_interface_gw

@ -22,8 +22,8 @@
#ifndef SRSLTE_MAC_SCH_PDU_NR_H #ifndef SRSLTE_MAC_SCH_PDU_NR_H
#define SRSLTE_MAC_SCH_PDU_NR_H #define SRSLTE_MAC_SCH_PDU_NR_H
#include "srslte/common/byte_buffer.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/logmap.h"
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/srslog/srslog.h" #include "srslte/srslog/srslog.h"
#include <memory> #include <memory>
@ -110,7 +110,7 @@ private:
static const uint8_t mac_ce_payload_len = 8 + 1; // Long BSR has max. 9 octets (see sizeof_ce() too) static const uint8_t mac_ce_payload_len = 8 + 1; // Long BSR has max. 9 octets (see sizeof_ce() too)
std::array<uint8_t, mac_ce_payload_len> ce_write_buffer; // Buffer for CE payload std::array<uint8_t, mac_ce_payload_len> ce_write_buffer; // Buffer for CE payload
mac_sch_pdu_nr* parent = nullptr; mac_sch_pdu_nr* parent = nullptr;
}; };
class mac_sch_pdu_nr class mac_sch_pdu_nr
@ -144,9 +144,9 @@ private:
bool ulsch = false; bool ulsch = false;
std::vector<mac_sch_subpdu_nr> subpdus; std::vector<mac_sch_subpdu_nr> subpdus;
byte_buffer_t* buffer = nullptr; byte_buffer_t* buffer = nullptr;
uint32_t pdu_len = 0; uint32_t pdu_len = 0;
uint32_t remaining_len = 0; uint32_t remaining_len = 0;
srslog::basic_logger& logger; srslog::basic_logger& logger;
}; };

@ -23,7 +23,6 @@
#define SRSLTE_PDU_H #define SRSLTE_PDU_H
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/logmap.h"
#include "srslte/srslog/srslog.h" #include "srslte/srslog/srslog.h"
#include <sstream> #include <sstream>
#include <stdint.h> #include <stdint.h>
@ -142,13 +141,12 @@ public:
{} {}
virtual ~pdu() = default; virtual ~pdu() = default;
std::string to_string() void to_string(fmt::memory_buffer& buffer)
{ {
std::stringstream ss;
for (int i = 0; i < nof_subheaders; i++) { for (int i = 0; i < nof_subheaders; i++) {
ss << subheaders[i].to_string() << " "; fmt::format_to(buffer, " ");
subheaders[i].to_string(buffer);
} }
return ss.str();
} }
/* Resets the Read/Write position and remaining PDU length */ /* Resets the Read/Write position and remaining PDU length */
@ -298,11 +296,11 @@ class subh
public: public:
virtual ~subh() {} virtual ~subh() {}
virtual bool read_subheader(uint8_t** ptr) = 0; virtual bool read_subheader(uint8_t** ptr) = 0;
virtual void read_payload(uint8_t** ptr) = 0; virtual void read_payload(uint8_t** ptr) = 0;
virtual void write_subheader(uint8_t** ptr, bool is_last) = 0; virtual void write_subheader(uint8_t** ptr, bool is_last) = 0;
virtual void write_payload(uint8_t** ptr) = 0; virtual void write_payload(uint8_t** ptr) = 0;
virtual std::string to_string() = 0; virtual void to_string(fmt::memory_buffer& buffer) = 0;
pdu<SubH>* parent = nullptr; pdu<SubH>* parent = nullptr;
@ -366,8 +364,8 @@ public:
void set_padding(uint32_t padding_len); void set_padding(uint32_t padding_len);
void set_type(subh_type type_); void set_type(subh_type type_);
void init(); void init();
std::string to_string(); void to_string(fmt::memory_buffer& buffer);
bool set_next_mch_sched_info(uint8_t lcid, uint16_t mtch_stop); bool set_next_mch_sched_info(uint8_t lcid, uint16_t mtch_stop);
@ -405,7 +403,7 @@ public:
static uint32_t size_header_sdu(uint32_t nbytes); static uint32_t size_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes, bool var_len = false); bool update_space_ce(uint32_t nbytes, bool var_len = false);
bool update_space_sdu(uint32_t nbytes); bool update_space_sdu(uint32_t nbytes);
std::string to_string(); void to_string(fmt::memory_buffer& buffer);
}; };
class rar_subh : public subh<rar_subh> class rar_subh : public subh<rar_subh>
@ -442,8 +440,8 @@ public:
void set_temp_crnti(uint16_t temp_rnti); void set_temp_crnti(uint16_t temp_rnti);
void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]); void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]);
void init(); void init();
std::string to_string(); void to_string(fmt::memory_buffer& buffer);
private: private:
uint8_t grant[RAR_GRANT_LEN]; uint8_t grant[RAR_GRANT_LEN];
@ -462,8 +460,8 @@ public:
bool has_backoff(); bool has_backoff();
uint8_t get_backoff(); uint8_t get_backoff();
bool write_packet(uint8_t* ptr); bool write_packet(uint8_t* ptr);
std::string to_string(); void to_string(fmt::memory_buffer& buffer);
private: private:
bool has_backoff_indicator; bool has_backoff_indicator;

@ -22,9 +22,9 @@
#ifndef SRSLTE_PDU_QUEUE_H #ifndef SRSLTE_PDU_QUEUE_H
#define SRSLTE_PDU_QUEUE_H #define SRSLTE_PDU_QUEUE_H
#include "srslte/adt/circular_buffer.h"
#include "srslte/common/block_queue.h" #include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "srslte/mac/pdu.h" #include "srslte/mac/pdu.h"
@ -42,9 +42,7 @@ public:
virtual void process_pdu(uint8_t* buff, uint32_t len, channel_t channel) = 0; virtual void process_pdu(uint8_t* buff, uint32_t len, channel_t channel) = 0;
}; };
pdu_queue(srslog::basic_logger& logger, uint32_t pool_size = DEFAULT_POOL_SIZE) : pdu_queue(srslog::basic_logger& logger) : pool(DEFAULT_POOL_SIZE), callback(NULL), logger(logger) {}
pool(pool_size), callback(NULL), logger(logger)
{}
void init(process_callback* callback); void init(process_callback* callback);
uint8_t* request(uint32_t len); uint8_t* request(uint32_t len);
@ -56,7 +54,7 @@ public:
void reset(); void reset();
private: private:
const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total const static int DEFAULT_POOL_SIZE = 128; // Number of PDU buffers in total
const static int MAX_PDU_LEN = 150 * 1024 / 8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150 * 1024 / 8; // ~ 150 Mbps
typedef struct { typedef struct {
@ -69,8 +67,8 @@ private:
} pdu_t; } pdu_t;
block_queue<pdu_t*> pdu_q; static_blocking_queue<pdu_t*, DEFAULT_POOL_SIZE> pdu_q;
buffer_pool<pdu_t> pool; buffer_pool<pdu_t> pool;
process_callback* callback; process_callback* callback;
srslog::basic_logger& logger; srslog::basic_logger& logger;

@ -29,6 +29,12 @@
#define SRSLTE_DMRS_SCH_MAX_SYMBOLS 4 #define SRSLTE_DMRS_SCH_MAX_SYMBOLS 4
/**
* @brief Helper macro for counting the number of subcarriers taken by DMRS in a PRB.
*/
#define SRSLTE_DMRS_SCH_SC(CDM_GROUPS, DMRS_TYPE) \
(SRSLTE_MIN(SRSLTE_NRE, (CDM_GROUPS) * ((DMRS_TYPE) == srslte_dmrs_sch_type_1 ? 6 : 4)))
/** /**
* @brief PDSCH DMRS estimator object * @brief PDSCH DMRS estimator object
* *

@ -27,8 +27,8 @@
#include "fading.h" #include "fading.h"
#include "hst.h" #include "hst.h"
#include "rlf.h" #include "rlf.h"
#include "srslte/common/log_filter.h"
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/srslog/srslog.h"
#include <memory> #include <memory>
#include <string> #include <string>

@ -44,10 +44,18 @@ SRSLTE_API int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg,
* @param nof_reports Number of CSI reports in the list * @param nof_reports Number of CSI reports in the list
* @return The number of bits if the provided list is valid, SRSLTE_ERROR code otherwise * @return The number of bits if the provided list is valid, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports); SRSLTE_API int srslte_csi_part1_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports);
/** /**
* @brief Pack CSI part 1 bits for a PUCCH transmission * @brief Checks if the report list contains part 2 CSI report
* @param report_list Report list
* @param nof_reports Number of reports in the list
* @return True if at least one report contains part 2, false otherwise
*/
SRSLTE_API bool srslte_csi_has_part2(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports);
/**
* @brief Pack CSI part 1 bits for a PUCCH or PUSCH transmission
* @param report_list Provides the CSI report list * @param report_list Provides the CSI report list
* @param nof_reports Number of CSI reports in the list * @param nof_reports Number of CSI reports in the list
* @param o_csi1 CSI bits * @param o_csi1 CSI bits
@ -60,6 +68,21 @@ SRSLTE_API int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg
uint8_t* o_csi1, uint8_t* o_csi1,
uint32_t max_o_csi1); uint32_t max_o_csi1);
/**
*@brief Unpacks CSI part 1 bits for PUCCH or PUSCH transmission
* @param report_list Provides the CSI report list
* @param nof_reports Number of CSI reports in the list
* @param o_csi1 CSI bits
* @param max_o_csi1 Maximum number of CSI bits
* @param report_value
* @return SRSLTE_SUCCESS if provided data is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_csi_part1_unpack(const srslte_csi_report_cfg_t* report_cfg,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1,
srslte_csi_report_value_t* report_value);
/** /**
* @brief Converts to string a given list of CSI reports * @brief Converts to string a given list of CSI reports
* @param report_cfg Report configuration list * @param report_cfg Report configuration list

@ -139,6 +139,7 @@ typedef struct SRSLTE_API {
// Resource set context // Resource set context
uint32_t nof_ports; ///< Number of antenna ports uint32_t nof_ports; ///< Number of antenna ports
uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set
bool has_part2; ///< Set to true if the report has part 2
} srslte_csi_report_cfg_t; } srslte_csi_report_cfg_t;
/** /**

@ -32,6 +32,7 @@
#include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/phch/sch_cfg_nr.h" #include "srslte/phy/phch/sch_cfg_nr.h"
#include "srslte/phy/phch/uci_cfg_nr.h"
/** /**
* @brief PDSCH DMRS type * @brief PDSCH DMRS type
@ -210,8 +211,13 @@ typedef struct SRSLTE_API {
srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters
/// Uplink params /// PUSCH only parameters
bool enable_transform_precoder; srslte_uci_cfg_nr_t uci; ///< Uplink Control Information configuration
bool enable_transform_precoder;
float beta_harq_ack_offset;
float beta_csi_part1_offset;
float scaling;
bool freq_hopping_enabled;
} srslte_sch_cfg_nr_t; } srslte_sch_cfg_nr_t;
#endif // SRSLTE_PHCH_CFG_NR_H #endif // SRSLTE_PHCH_CFG_NR_H

@ -51,6 +51,7 @@ typedef struct SRSLTE_API {
*/ */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint32_t max_prb; uint32_t max_prb;
srslte_carrier_nr_t carrier;
srslte_zc_sequence_lut_t r_uv_1prb; srslte_zc_sequence_lut_t r_uv_1prb;
cf_t format1_w_i_m[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX]; cf_t format1_w_i_m[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX];
srslte_modem_table_t bpsk; srslte_modem_table_t bpsk;
@ -64,10 +65,19 @@ typedef struct SRSLTE_API {
/** /**
* @brief Initialises an NR-PUCCH encoder/decoder object * @brief Initialises an NR-PUCCH encoder/decoder object
* @param q Object * @param q Object
* @param args PUCCH configuration arguments
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* args); SRSLTE_API int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* args);
/**
* @brief Initialises an NR-PUCCH encoder/decoder object
* @param q Object
* @param carrier
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_pucch_nr_set_carrier(srslte_pucch_nr_t* q, const srslte_carrier_nr_t* carrier);
/** /**
* @brief Deallocates an NR-PUCCH encoder/decoder object * @brief Deallocates an NR-PUCCH encoder/decoder object
* @param q Object * @param q Object
@ -113,7 +123,6 @@ SRSLTE_API int srslte_pucch_nr_alpha_idx(const srslte_carrier_nr_t* car
* @brief Encode and writes NR-PUCCH format 0 in the resource grid * @brief Encode and writes NR-PUCCH format 0 in the resource grid
* @remark Described in TS 38.211 clause 6.3.2.3 PUCCH format 0 * @remark Described in TS 38.211 clause 6.3.2.3 PUCCH format 0
* @param[in,out] q NR-PUCCH encoder/decoder object * @param[in,out] q NR-PUCCH encoder/decoder object
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 0 resource * @param[in] resource PUCCH format 0 resource
@ -122,7 +131,6 @@ SRSLTE_API int srslte_pucch_nr_alpha_idx(const srslte_carrier_nr_t* car
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
srslte_pucch_nr_resource_t* resource, srslte_pucch_nr_resource_t* resource,
@ -132,7 +140,6 @@ SRSLTE_API int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t*
/** /**
* @brief Measures PUCCH format 0 in the resource grid * @brief Measures PUCCH format 0 in the resource grid
* @param[in,out] q NR-PUCCH encoder/decoder object * @param[in,out] q NR-PUCCH encoder/decoder object
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 0 resource * @param[in] resource PUCCH format 0 resource
@ -142,7 +149,6 @@ SRSLTE_API int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t*
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
srslte_pucch_nr_resource_t* resource, srslte_pucch_nr_resource_t* resource,
@ -165,7 +171,6 @@ SRSLTE_API cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n
* @brief Encodes and puts NR-PUCCH format 1 in the resource grid * @brief Encodes and puts NR-PUCCH format 1 in the resource grid
* @remark Described in TS 38.211 clause 6.3.2.4 PUCCH format 1 * @remark Described in TS 38.211 clause 6.3.2.4 PUCCH format 1
* @param[in,out] q NR-PUCCH encoder/decoder object * @param[in,out] q NR-PUCCH encoder/decoder object
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 1 resource * @param[in] resource PUCCH format 1 resource
@ -175,7 +180,6 @@ SRSLTE_API cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -186,7 +190,6 @@ SRSLTE_API int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t*
/** /**
* @brief Decodes NR-PUCCH format 1 * @brief Decodes NR-PUCCH format 1
* @param[in,out] q NR-PUCCH encoder/decoder object * @param[in,out] q NR-PUCCH encoder/decoder object
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 2-4 resource * @param[in] resource PUCCH format 2-4 resource
@ -197,7 +200,6 @@ SRSLTE_API int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t*
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -209,7 +211,6 @@ SRSLTE_API int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t*
/** /**
* @brief Encoder NR-PUCCH formats 2, 3 and 4. The NR-PUCCH format is selected by resource->format. * @brief Encoder NR-PUCCH formats 2, 3 and 4. The NR-PUCCH format is selected by resource->format.
* @param[in,out] q NR-PUCCH encoder/decoder object * @param[in,out] q NR-PUCCH encoder/decoder object
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 1 resource * @param[in] resource PUCCH format 1 resource
@ -219,7 +220,6 @@ SRSLTE_API int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t*
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -230,7 +230,6 @@ SRSLTE_API int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t*
/** /**
* @brief Decode NR-PUCCH format 2, 3, and 4. The NR-PUCCH format is selected by resource->format. * @brief Decode NR-PUCCH format 2, 3, and 4. The NR-PUCCH format is selected by resource->format.
* @param q[in,out] q NR-PUCCH encoder/decoder * @param q[in,out] q NR-PUCCH encoder/decoder
* @param[in] carrier Serving cell and Uplink BWP configuration
* @param[in] cfg PUCCH common configuration * @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration * @param[in] slot slot configuration
* @param[in] resource PUCCH format 2-4 resource * @param[in] resource PUCCH format 2-4 resource
@ -241,7 +240,6 @@ SRSLTE_API int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t*
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise * @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/ */
SRSLTE_API int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q, SRSLTE_API int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,

@ -29,6 +29,7 @@
#include "srslte/phy/phch/phch_cfg_nr.h" #include "srslte/phy/phch/phch_cfg_nr.h"
#include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/regs.h"
#include "srslte/phy/phch/sch_nr.h" #include "srslte/phy/phch/sch_nr.h"
#include "srslte/phy/phch/uci_nr.h"
#include "srslte/phy/scrambling/scrambling.h" #include "srslte/phy/scrambling/scrambling.h"
/** /**
@ -36,6 +37,7 @@
*/ */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_sch_nr_args_t sch; srslte_sch_nr_args_t sch;
srslte_uci_nr_args_t uci;
bool measure_evm; bool measure_evm;
bool measure_time; bool measure_time;
} srslte_pusch_nr_args_t; } srslte_pusch_nr_args_t;
@ -49,6 +51,7 @@ typedef struct SRSLTE_API {
uint32_t max_cw; ///< Maximum number of allocated code words uint32_t max_cw; ///< Maximum number of allocated code words
srslte_carrier_nr_t carrier; ///< NR carrier configuration srslte_carrier_nr_t carrier; ///< NR carrier configuration
srslte_sch_nr_t sch; ///< SCH Encoder/Decoder Object srslte_sch_nr_t sch; ///< SCH Encoder/Decoder Object
srslte_uci_nr_t uci; ///< UCI Encoder/Decoder Object
uint8_t* b[SRSLTE_MAX_CODEWORDS]; ///< SCH Encoded and scrambled data uint8_t* b[SRSLTE_MAX_CODEWORDS]; ///< SCH Encoded and scrambled data
cf_t* d[SRSLTE_MAX_CODEWORDS]; ///< PDSCH modulated bits cf_t* d[SRSLTE_MAX_CODEWORDS]; ///< PDSCH modulated bits
cf_t* x[SRSLTE_MAX_LAYERS_NR]; ///< PDSCH modulated bits cf_t* x[SRSLTE_MAX_LAYERS_NR]; ///< PDSCH modulated bits
@ -56,15 +59,38 @@ typedef struct SRSLTE_API {
srslte_evm_buffer_t* evm_buffer; srslte_evm_buffer_t* evm_buffer;
bool meas_time_en; bool meas_time_en;
uint32_t meas_time_us; uint32_t meas_time_us;
srslte_uci_cfg_nr_t uci_cfg; ///< Internal UCI bits configuration
uint8_t* g_ulsch; ///< Temporal Encoded UL-SCH data
uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits
uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits
uint8_t* g_csi2; ///< Temporal Encoded CSI part 2 bits
uint32_t* pos_ulsch; ///< Reserved resource elements for HARQ-ACK multiplexing position
uint32_t* pos_ack; ///< Reserved resource elements for HARQ-ACK multiplexing position
uint32_t* pos_csi1; ///< Reserved resource elements for CSI part 1 multiplexing position
uint32_t* pos_csi2; ///< Reserved resource elements for CSI part 1 multiplexing position
bool uci_mux; ///< Set to true if PUSCH needs to multiplex UCI
uint32_t G_ack; ///< Number of encoded HARQ-ACK bits
uint32_t G_csi1; ///< Number of encoded CSI part 1 bits
uint32_t G_csi2; ///< Number of encoded CSI part 2 bits
uint32_t G_ulsch; ///< Number of encoded shared channel
} srslte_pusch_nr_t; } srslte_pusch_nr_t;
/** /**
* * @brief Groups NR-PUSCH data for transmission
*/ */
typedef struct { typedef struct {
uint8_t* payload; uint8_t* payload; ///< SCH payload
bool crc; srslte_uci_value_nr_t uci; ///< UCI payload
float evm; } srslte_pusch_data_nr_t;
/**
* @brief Groups NR-PUSCH data for reception
*/
typedef struct {
uint8_t* payload; ///< SCH payload
srslte_uci_value_nr_t uci; ///< UCI payload
bool crc; ///< CRC match
float evm; ///< EVM measurement if configured through arguments
} srslte_pusch_res_nr_t; } srslte_pusch_res_nr_t;
SRSLTE_API int srslte_pusch_nr_init_gnb(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* args); SRSLTE_API int srslte_pusch_nr_init_gnb(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* args);
@ -75,11 +101,11 @@ SRSLTE_API void srslte_pusch_nr_free(srslte_pusch_nr_t* q);
SRSLTE_API int srslte_pusch_nr_set_carrier(srslte_pusch_nr_t* q, const srslte_carrier_nr_t* carrier); SRSLTE_API int srslte_pusch_nr_set_carrier(srslte_pusch_nr_t* q, const srslte_carrier_nr_t* carrier);
SRSLTE_API int srslte_pusch_nr_encode(srslte_pusch_nr_t* q, SRSLTE_API int srslte_pusch_nr_encode(srslte_pusch_nr_t* q,
const srslte_sch_cfg_nr_t* cfg, const srslte_sch_cfg_nr_t* cfg,
const srslte_sch_grant_nr_t* grant, const srslte_sch_grant_nr_t* grant,
uint8_t* data[SRSLTE_MAX_TB], const srslte_pusch_data_nr_t* data,
cf_t* sf_symbols[SRSLTE_MAX_PORTS]); cf_t* sf_symbols[SRSLTE_MAX_PORTS]);
SRSLTE_API int srslte_pusch_nr_decode(srslte_pusch_nr_t* q, SRSLTE_API int srslte_pusch_nr_decode(srslte_pusch_nr_t* q,
const srslte_sch_cfg_nr_t* cfg, const srslte_sch_cfg_nr_t* cfg,

@ -61,7 +61,7 @@ SRSLTE_API int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg,
* @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code
*/ */
SRSLTE_API int SRSLTE_API int
srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant); srslte_ra_ul_nr_pusch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant);
/** /**
* @brief Calculates the number of PUSCH-DMRS CDM groups without data for DCI format 0_0 * @brief Calculates the number of PUSCH-DMRS CDM groups without data for DCI format 0_0

@ -78,27 +78,24 @@ typedef struct SRSLTE_API {
* @brief Common SCH configuration * @brief Common SCH configuration
*/ */
typedef struct { typedef struct {
srslte_basegraph_t bg; ///< @brief Base graph srslte_basegraph_t bg; ///< @brief Base graph
uint32_t Qm; ///< @brief Modulation order uint32_t Qm; ///< @brief Modulation order
uint32_t G; ///< Number of available bits uint32_t G; ///< Number of available bits
uint32_t A; ///< @brief Payload size, TBS uint32_t A; ///< @brief Payload size, TBS
uint32_t L_tb; ///< @brief the number of the transport block parity bits (16 or 24 bits) uint32_t L_tb; ///< @brief the number of the transport block parity bits (16 or 24 bits)
uint32_t L_cb; ///< @brief the number of the code block parity bits (0 or 24 bits) uint32_t L_cb; ///< @brief the number of the code block parity bits (0 or 24 bits)
uint32_t B; ///< @brief the number of bits in the transport block including TB CRC uint32_t B; ///< @brief the number of bits in the transport block including TB CRC
uint32_t Bp; ///< @brief the number of bits in the transport block including CB and TB CRCs uint32_t Bp; ///< @brief the number of bits in the transport block including CB and TB CRCs
uint32_t Kp; ///< @brief Number of payload bits of the code block including CB CRC uint32_t Kp; ///< @brief Number of payload bits of the code block including CB CRC
uint32_t Kr; ///< @brief Number of payload bits of the code block including CB CRC and filler bits uint32_t Kr; ///< @brief Number of payload bits of the code block including CB CRC and filler bits
uint32_t F; ///< @brief Number of filler bits uint32_t F; ///< @brief Number of filler bits
uint32_t Nref; ///< @brief N_ref parameter described in TS 38.212 V15.9.0 5.4.2.1 uint32_t Nref; ///< @brief N_ref parameter described in TS 38.212 V15.9.0 5.4.2.1
uint32_t Z; ///< @brief LDPC lifting size uint32_t Z; ///< @brief LDPC lifting size
uint32_t Nl; ///< @brief Number of transmission layers that the transport block is mapped onto uint32_t Nl; ///< @brief Number of transmission layers that the transport block is mapped onto
bool mask[SRSLTE_SCH_NR_MAX_NOF_CB_LDPC]; ///< Indicates what codeblocks shall be encoded/decoded bool mask[SRSLTE_SCH_NR_MAX_NOF_CB_LDPC]; ///< Indicates what codeblocks shall be encoded/decoded
uint32_t C; ///< Number of codeblocks uint32_t C; ///< Number of codeblocks
uint32_t Cp; ///< Number of codeblocks that are actually transmitted uint32_t Cp; ///< Number of codeblocks that are actually transmitted
srslte_crc_t* crc_tb; ///< Selected CRC for transport block } srslte_sch_nr_tb_info_t;
srslte_ldpc_encoder_t* encoder; ///< @brief Points to the selected encoder (if valid)
srslte_ldpc_decoder_t* decoder; ///< @brief Points to the selected decoder (if valid)
} srslte_sch_nr_common_cfg_t;
/** /**
* @brief Base graph selection from a provided transport block size and target rate * @brief Base graph selection from a provided transport block size and target rate
@ -119,10 +116,10 @@ SRSLTE_API srslte_basegraph_t srslte_sch_nr_select_basegraph(uint32_t tbs, doubl
* @param cfg SCH object * @param cfg SCH object
* @return * @return
*/ */
SRSLTE_API int srslte_sch_nr_fill_cfg(srslte_sch_nr_t* q, SRSLTE_API int srslte_sch_nr_fill_tb_info(const srslte_carrier_nr_t* carrier,
const srslte_sch_cfg_t* sch_cfg, const srslte_sch_cfg_t* sch_cfg,
const srslte_sch_tb_t* tb, const srslte_sch_tb_t* tb,
srslte_sch_nr_common_cfg_t* cfg); srslte_sch_nr_tb_info_t* cfg);
/** /**
* @brief Initialises an SCH object as transmitter * @brief Initialises an SCH object as transmitter

@ -23,7 +23,7 @@
#define SRSLTE_UCI_CFG_NR_H #define SRSLTE_UCI_CFG_NR_H
#include "csi_cfg.h" #include "csi_cfg.h"
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common_nr.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -39,21 +39,41 @@
#define SRSLTE_UCI_NR_MAX_ACK_BITS 360 #define SRSLTE_UCI_NR_MAX_ACK_BITS 360
/** /**
* @brief Maximum number of Scheduling Request (SR) bits that can be carried in Uplink Control Information (UCI) message * @brief Maximum number of Channel State Information part 1 (CSI1) bits that can be carried in Uplink Control
* Information (UCI) message
*/ */
#define SRSLTE_UCI_NR_MAX_SR_BITS 10 #define SRSLTE_UCI_NR_MAX_CSI1_BITS 360
/** /**
* @brief Maximum number of Channel State Information part 1 (CSI1) bits that can be carried in Uplink Control * @brief Uplink Control Information bits configuration for PUCCH transmission
* Information (UCI) message
*/ */
#define SRSLTE_UCI_NR_MAX_CSI1_BITS 10 typedef struct {
uint16_t rnti; ///< RNTI
uint32_t resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1
uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception
uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1
uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR
bool sr_positive_present; ///< Set to true if there is at least one positive SR
} srslte_uci_nr_pucch_cfg_t;
/** /**
* @brief Maximum number of Channel State Information part 2 (CSI2) bits that can be carried in Uplink Control * @brief Uplink Control Information bits configuration for PUSCH transmission
* Information (UCI) message
*/ */
#define SRSLTE_UCI_NR_MAX_CSI2_BITS 10 typedef struct {
uint32_t l0; ///< First OFDM symbol that does not carry DMRS of the PUSCH, after the first DMRS symbol(s)
uint32_t l1; ///< OFDM symbol index of the first OFDM symbol that does not carry DMRS
uint32_t M_pusch_sc[SRSLTE_NSYMB_PER_SLOT_NR]; ///< Number of potential RE for PUSCH transmission
uint32_t M_uci_sc[SRSLTE_NSYMB_PER_SLOT_NR]; ///< Number of potential RE for UCI transmission
uint32_t K_sum; ///< Sum of UL-SCH code block sizes, set to zero if no UL-SCH
srslte_mod_t modulation; ///< Modulation for the PUSCH
uint32_t nof_layers; ///< Number of layers for PUSCH
float R; ///< Code rate of the PUSCH
float alpha; ///< Higher layer parameter scaling
float beta_harq_ack_offset;
float beta_csi1_offset;
uint32_t nof_re;
bool csi_part2_present;
} srslte_uci_nr_pusch_cfg_t;
/** /**
* @brief Uplink Control Information (UCI) message configuration * @brief Uplink Control Information (UCI) message configuration
@ -64,17 +84,10 @@ typedef struct SRSLTE_API {
uint32_t o_sr; ///< Number of SR bits uint32_t o_sr; ///< Number of SR bits
srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration
uint32_t nof_csi; ///< Number of CSI reports uint32_t nof_csi; ///< Number of CSI reports
union {
/// PUSCH only parameters srslte_uci_nr_pucch_cfg_t pucch; ///< Configuration for transmission in PUCCH
srslte_mod_t modulation; ///< Modulation srslte_uci_nr_pusch_cfg_t pusch; ///< Configuration for transmission in PUSCH
};
/// PUCCH only parameters
uint16_t rnti; ///< RNTI
uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1
uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception
uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1
uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR
bool sr_positive_present; ///< Set to true if there is at least one positive SR
} srslte_uci_cfg_nr_t; } srslte_uci_cfg_nr_t;
/** /**

@ -22,13 +22,14 @@
#ifndef SRSLTE_UCI_NR_H #ifndef SRSLTE_UCI_NR_H
#define SRSLTE_UCI_NR_H #define SRSLTE_UCI_NR_H
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/fec/crc.h" #include "srslte/phy/fec/crc.h"
#include "srslte/phy/fec/polar/polar_code.h" #include "srslte/phy/fec/polar/polar_code.h"
#include "srslte/phy/fec/polar/polar_decoder.h" #include "srslte/phy/fec/polar/polar_decoder.h"
#include "srslte/phy/fec/polar/polar_encoder.h" #include "srslte/phy/fec/polar/polar_encoder.h"
#include "srslte/phy/fec/polar/polar_rm.h" #include "srslte/phy/fec/polar/polar_rm.h"
#include "srslte/phy/phch/phch_cfg_nr.h"
#include "srslte/phy/phch/pucch_cfg_nr.h" #include "srslte/phy/phch/pucch_cfg_nr.h"
#include "uci_cfg.h"
#include "uci_cfg_nr.h" #include "uci_cfg_nr.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -39,6 +40,7 @@
typedef struct { typedef struct {
bool disable_simd; ///< Disable Polar code SIMD bool disable_simd; ///< Disable Polar code SIMD
float block_code_threshold; ///< Set normalised block code threshold (receiver only) float block_code_threshold; ///< Set normalised block code threshold (receiver only)
float one_bit_threshold; ///< Decode threshold for 1 bit (receiver only)
} srslte_uci_nr_args_t; } srslte_uci_nr_args_t;
typedef struct { typedef struct {
@ -49,11 +51,12 @@ typedef struct {
srslte_crc_t crc6; srslte_crc_t crc6;
srslte_crc_t crc11; srslte_crc_t crc11;
srslte_polar_code_t code; srslte_polar_code_t code;
uint8_t* bit_sequence; ///< UCI bit sequence uint8_t* bit_sequence; ///< UCI bit sequence
uint8_t* c; ///< UCI code-block prior encoding or after decoding uint8_t* c; ///< UCI code-block prior encoding or after decoding
uint8_t* allocated; ///< Polar code intermediate uint8_t* allocated; ///< Polar code intermediate
uint8_t* d; ///< Polar code encoded intermediate uint8_t* d; ///< Polar code encoded intermediate
float block_code_threshold; float block_code_threshold; ///< Decode threshold for block code (3-11 bits)
float one_bit_threshold; ///< Decode threshold for 1 bit
} srslte_uci_nr_t; } srslte_uci_nr_t;
/** /**
@ -123,6 +126,72 @@ SRSLTE_API int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
int8_t* llr, int8_t* llr,
srslte_uci_value_nr_t* value); srslte_uci_value_nr_t* value);
/**
* @brief Calculates total number of encoded bits for HARQ-ACK multiplexing in PUSCH
* @param[in] cfg PUSCH transmission configuration
* @return The number of encoded bits if successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_pusch_ack_nof_bits(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack);
/**
* @brief Encodes HARQ-ACK bits for PUSCH transmission
* @param[in,out] q NR-UCI object
* @param[in] cfg UCI configuration
* @param[in] value UCI value
* @param[out] o_ack Encoded ack bits
* @return The number of encoded bits if successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_encode_pusch_ack(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o_ack);
/**
* @brief Decodes HARQ-ACK bits for PUSCH transmission
* @param[in,out] q NR-UCI object
* @param[in] cfg UCI configuration
* @param[in] llr Provides softbits LLR
* @param[out] value UCI value
* @return SRSLTE_SUCCESS if the decoding process was successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_decode_pusch_ack(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
int8_t* llr,
srslte_uci_value_nr_t* value);
/**
* @brief Calculates total number of encoded bits for CSI part 1 multiplexing in PUSCH
* @param[in] cfg UCI configuration
* @return The number of encoded bits if valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_pusch_csi1_nof_bits(const srslte_uci_cfg_nr_t* cfg);
/**
* @brief Encodes CSI part 1 bits for PUSCH transmission
* @param[in,out] q NR-UCI object
* @param[in] cfg UCI configuration
* @param[in] value UCI value
* @param[out] o_ack Encoded CSI part 1 bits
* @return The number of encoded bits if successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_encode_pusch_csi1(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o);
/**
* @brief Decodes CSI part 1 bits for PUSCH transmission
* @param[in,out] q NR-UCI object
* @param[in] cfg UCI configuration
* @param[in] llr Provides softbits LLR
* @param[out] value UCI value
* @return SRSLTE_SUCCESS if the decoding process was successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_decode_pusch_csi1(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
int8_t* llr,
srslte_uci_value_nr_t* value);
/** /**
* @brief Calculates the total number of UCI bits * @brief Calculates the total number of UCI bits
* @param uci_cfg UCI configuration * @param uci_cfg UCI configuration

@ -63,10 +63,10 @@ SRSLTE_API int srslte_ue_ul_nr_init(srslte_ue_ul_nr_t* q, cf_t* output, const sr
SRSLTE_API int srslte_ue_ul_nr_set_carrier(srslte_ue_ul_nr_t* q, const srslte_carrier_nr_t* carrier); SRSLTE_API int srslte_ue_ul_nr_set_carrier(srslte_ue_ul_nr_t* q, const srslte_carrier_nr_t* carrier);
SRSLTE_API int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q, SRSLTE_API int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot_cfg, const srslte_slot_cfg_t* slot_cfg,
const srslte_sch_cfg_nr_t* pusch_cfg, const srslte_sch_cfg_nr_t* pusch_cfg,
uint8_t* data_); const srslte_pusch_data_nr_t* data);
SRSLTE_API int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q, SRSLTE_API int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot_cfg, const srslte_slot_cfg_t* slot_cfg,

@ -49,6 +49,9 @@ extern "C" {
#define SRSLTE_MAX(a, b) ((a) > (b) ? (a) : (b)) #define SRSLTE_MAX(a, b) ((a) > (b) ? (a) : (b))
#define SRSLTE_MIN(a, b) ((a) < (b) ? (a) : (b)) #define SRSLTE_MIN(a, b) ((a) < (b) ? (a) : (b))
#define SRSLTE_CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
#define SRSLTE_FLOOR(NUM, DEN) ((NUM) / (DEN))
#define SRSLTE_ROUND(NUM, DEN) ((uint32_t)round((double)(NUM) / (double)(DEN)))
// Cumulative moving average // Cumulative moving average
#define SRSLTE_VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n) + 1)) #define SRSLTE_VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n) + 1))

@ -24,12 +24,13 @@
#include "rf_buffer.h" #include "rf_buffer.h"
#include "rf_timestamp.h" #include "rf_timestamp.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log_filter.h"
#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/radio_interfaces.h"
#include "srslte/phy/resampling/resampler.h" #include "srslte/phy/resampling/resampler.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#include "srslte/radio/radio_base.h" #include "srslte/radio/radio_base.h"
#include "srslte/srslog/srslog.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <list> #include <list>
#include <string> #include <string>

@ -28,7 +28,6 @@
#define SRSLTE_RADIO_BASE_H #define SRSLTE_RADIO_BASE_H
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/logger.h"
#include "srslte/radio/radio_metrics.h" #include "srslte/radio/radio_metrics.h"
namespace srslte { namespace srslte {

@ -28,8 +28,6 @@
#define SRSLTE_RADIO_NULL_H #define SRSLTE_RADIO_NULL_H
#include "radio_base.h" #include "radio_base.h"
#include "srslte/common/logger.h"
#include "srslte/common/logmap.h"
#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/radio_interfaces.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"

@ -24,7 +24,6 @@
#include "srslte/asn1/rrc_utils.h" #include "srslte/asn1/rrc_utils.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/logmap.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>

@ -42,7 +42,7 @@ struct log_context {
struct log_entry_metadata { struct log_entry_metadata {
std::chrono::high_resolution_clock::time_point tp; std::chrono::high_resolution_clock::time_point tp;
log_context context; log_context context;
std::string fmtstring; const char* fmtstring;
fmt::dynamic_format_arg_store<fmt::printf_context> store; fmt::dynamic_format_arg_store<fmt::printf_context> store;
std::string log_name; std::string log_name;
char log_tag; char log_tag;

@ -37,18 +37,22 @@ class memory_buffer
public: public:
memory_buffer(const char* buffer, size_t length) : memory_buffer(const char* buffer, size_t length) :
buffer(buffer), buffer(buffer), length(length)
length(length)
{} {}
explicit memory_buffer(const std::string& s) : explicit memory_buffer(const std::string& s) :
buffer(s.data()), buffer(s.data()), length(s.size())
length(s.size())
{} {}
/// Returns a pointer to the start of the memory block. /// Returns a pointer to the start of the memory block.
const char* data() const { return buffer; } const char* data() const { return buffer; }
/// Returns an iterator to the beginning of the buffer.
const char* begin() const { return buffer; }
/// Returns an iterator to the end of the buffer.
const char* end() const { return buffer + length; }
/// Returns the size of the memory block. /// Returns the size of the memory block.
size_t size() const { return length; } size_t size() const { return length; }
}; };

@ -60,8 +60,8 @@ public:
return false; return false;
} }
queue.push(value); queue.push(value);
cond_var.signal();
cond_var.unlock(); cond_var.unlock();
cond_var.signal();
return true; return true;
} }
@ -77,8 +77,8 @@ public:
return false; return false;
} }
queue.push(std::move(value)); queue.push(std::move(value));
cond_var.signal();
cond_var.unlock(); cond_var.unlock();
cond_var.signal();
return true; return true;
} }

@ -45,6 +45,13 @@ void event_trace_init();
/// all trace events. /// all trace events.
void event_trace_init(log_channel& c); void event_trace_init(log_channel& c);
/// Initializes the event trace framework.
/// The event trace data will be written into the specified filename after
/// capacity bytes of data have been generated or at program exit.
/// Returns true on success, otherwise false.
bool event_trace_init(const std::string& filename,
std::size_t capacity = 1024 * 1024);
#ifdef ENABLE_SRSLOG_EVENT_TRACE #ifdef ENABLE_SRSLOG_EVENT_TRACE
/// Generates the begin phase of a duration event. /// Generates the begin phase of a duration event.
@ -54,8 +61,11 @@ void trace_duration_begin(const std::string& category, const std::string& name);
void trace_duration_end(const std::string& category, const std::string& name); void trace_duration_end(const std::string& category, const std::string& name);
/// Generates a complete event. /// Generates a complete event.
#define SRSLOG_TRACE_COMBINE1(X, Y) X##Y
#define SRSLOG_TRACE_COMBINE(X, Y) SRSLOG_TRACE_COMBINE1(X, Y)
#define trace_complete_event(C, N) \ #define trace_complete_event(C, N) \
auto scoped_complete_event_variable = detail::scoped_complete_event(C, N) auto SRSLOG_TRACE_COMBINE(scoped_complete_event, __LINE__) = \
srslog::detail::scoped_complete_event(C, N)
#else #else
@ -72,17 +82,15 @@ namespace detail {
class scoped_complete_event class scoped_complete_event
{ {
public: public:
scoped_complete_event(std::string cat, std::string n) : scoped_complete_event(const char* cat, const char* n) :
category(std::move(cat)), category(cat), name(n), start(std::chrono::steady_clock::now())
name(std::move(n)),
start(std::chrono::steady_clock::now())
{} {}
~scoped_complete_event(); ~scoped_complete_event();
private: private:
const std::string category; const char* const category;
const std::string name; const char* const name;
std::chrono::time_point<std::chrono::steady_clock> start; std::chrono::time_point<std::chrono::steady_clock> start;
}; };

@ -98,7 +98,7 @@ public:
/// Builds the provided log entry and passes it to the backend. When the /// Builds the provided log entry and passes it to the backend. When the
/// channel is disabled the log entry will be discarded. /// channel is disabled the log entry will be discarded.
template <typename... Args> template <typename... Args>
void operator()(const std::string& fmtstr, Args&&... args) void operator()(const char* fmtstr, Args&&... args)
{ {
if (!enabled()) { if (!enabled()) {
return; return;
@ -106,7 +106,8 @@ public:
// Populate the store with all incoming arguments. // Populate the store with all incoming arguments.
fmt::dynamic_format_arg_store<fmt::printf_context> store; fmt::dynamic_format_arg_store<fmt::printf_context> store;
(void)std::initializer_list<int>{(store.push_back(args), 0)...}; (void)std::initializer_list<int>{
(store.push_back(std::forward<Args>(args)), 0)...};
// Send the log entry to the backend. // Send the log entry to the backend.
log_formatter& formatter = log_sink.get_formatter(); log_formatter& formatter = log_sink.get_formatter();
@ -130,7 +131,7 @@ public:
template <typename... Args> template <typename... Args>
void operator()(const uint8_t* buffer, void operator()(const uint8_t* buffer,
size_t len, size_t len,
const std::string& fmtstr, const char* fmtstr,
Args&&... args) Args&&... args)
{ {
if (!enabled()) { if (!enabled()) {
@ -139,7 +140,8 @@ public:
// Populate the store with all incoming arguments. // Populate the store with all incoming arguments.
fmt::dynamic_format_arg_store<fmt::printf_context> store; fmt::dynamic_format_arg_store<fmt::printf_context> store;
(void)std::initializer_list<int>{(store.push_back(args), 0)...}; (void)std::initializer_list<int>{
(store.push_back(std::forward<Args>(args)), 0)...};
// Calculate the length to capture in the buffer. // Calculate the length to capture in the buffer.
if (hex_max_size >= 0) if (hex_max_size >= 0)
@ -182,7 +184,7 @@ public:
}, },
{std::chrono::high_resolution_clock::now(), {std::chrono::high_resolution_clock::now(),
{ctx_value, should_print_context}, {ctx_value, should_print_context},
"", nullptr,
{}, {},
log_name, log_name,
log_tag}}; log_tag}};
@ -192,9 +194,7 @@ public:
/// Builds the provided log entry and passes it to the backend. When the /// Builds the provided log entry and passes it to the backend. When the
/// channel is disabled the log entry will be discarded. /// channel is disabled the log entry will be discarded.
template <typename... Ts, typename... Args> template <typename... Ts, typename... Args>
void operator()(const context<Ts...>& ctx, void operator()(const context<Ts...>& ctx, const char* fmtstr, Args&&... args)
const std::string& fmtstr,
Args&&... args)
{ {
if (!enabled()) { if (!enabled()) {
return; return;
@ -202,7 +202,8 @@ public:
// Populate the store with all incoming arguments. // Populate the store with all incoming arguments.
fmt::dynamic_format_arg_store<fmt::printf_context> store; fmt::dynamic_format_arg_store<fmt::printf_context> store;
(void)std::initializer_list<int>{(store.push_back(args), 0)...}; (void)std::initializer_list<int>{
(store.push_back(std::forward<Args>(args)), 0)...};
// Send the log entry to the backend. // Send the log entry to the backend.
log_formatter& formatter = log_sink.get_formatter(); log_formatter& formatter = log_sink.get_formatter();

@ -37,7 +37,7 @@ class logger_impl : public T
{ {
static_assert(std::is_enum<Enum>::value, "Expected enum type"); static_assert(std::is_enum<Enum>::value, "Expected enum type");
using enum_base_type = typename std::underlying_type<Enum>::type; using enum_base_type = typename std::underlying_type<Enum>::type;
static constexpr unsigned size = static_cast<enum_base_type>(Enum::LAST) - 1; static constexpr unsigned size = static_cast<enum_base_type>(Enum::LAST) - 1;
public: public:
@ -45,9 +45,7 @@ public:
explicit logger_impl(std::string id, Args&&... args) : explicit logger_impl(std::string id, Args&&... args) :
T{std::forward<Args>(args)...}, logger_id(std::move(id)), channels{&args...} T{std::forward<Args>(args)...}, logger_id(std::move(id)), channels{&args...}
{ {
static_assert( static_assert(sizeof...(args) == size, "Number of levels in enum does not match number of log channels");
sizeof...(args) == size,
"Number of levels in enum does not match number of log channels");
} }
logger_impl(const logger_impl& other) = delete; logger_impl(const logger_impl& other) = delete;
@ -102,16 +100,16 @@ private:
} }
private: private:
const std::string logger_id; const std::string logger_id;
const std::array<log_channel*, size> channels; const std::array<log_channel*, size> channels;
mutable detail::mutex m; mutable detail::mutex m;
}; };
/// Type trait to detect if T is a logger. /// Type trait to detect if T is a logger.
template <typename T> template <typename T>
struct is_logger : std::false_type {}; struct is_logger : std::false_type {};
template <typename T, typename Enum> template <typename T, typename Enum>
struct is_logger<logger_impl<T, Enum>> : std::true_type {}; struct is_logger<logger_impl<T, Enum> > : std::true_type {};
} // namespace detail } // namespace detail
@ -182,6 +180,24 @@ inline basic_levels str_to_basic_level(std::string s)
return basic_levels::none; return basic_levels::none;
} }
/// Translates a logger basic level to the corresponding string.
inline const char* basic_level_to_string(basic_levels level)
{
switch (level) {
case basic_levels::debug:
return "DEBUG";
case basic_levels::info:
return "INFO";
case basic_levels::warning:
return "WARNING";
case basic_levels::error:
return "ERROR";
default:
break;
}
return "NONE";
}
} // namespace srslog } // namespace srslog
#endif // SRSLOG_LOGGER_H #endif // SRSLOG_LOGGER_H

@ -30,51 +30,43 @@
#ifndef SRSLTE_BYTE_BUFFERQUEUE_H #ifndef SRSLTE_BYTE_BUFFERQUEUE_H
#define SRSLTE_BYTE_BUFFERQUEUE_H #define SRSLTE_BYTE_BUFFERQUEUE_H
#include "srslte/adt/circular_buffer.h"
#include "srslte/common/block_queue.h" #include "srslte/common/block_queue.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include <pthread.h> #include <pthread.h>
namespace srslte { namespace srslte {
class byte_buffer_queue : public block_queue<unique_byte_buffer_t>::call_mutexed_itf class byte_buffer_queue
{ {
public: public:
byte_buffer_queue(int capacity = 128) : queue(capacity) { queue.set_mutexed_itf(this); } byte_buffer_queue(int capacity = 128) : queue(capacity, push_callback(unread_bytes), pop_callback(unread_bytes)) {}
// increase/decrease unread_bytes inside push/pop mutexed operations
void pushing(const unique_byte_buffer_t& msg) final { unread_bytes += msg->N_bytes; } void write(unique_byte_buffer_t msg) { queue.push_blocking(std::move(msg)); }
void popping(const unique_byte_buffer_t& msg) final
{
if (unread_bytes > msg->N_bytes) {
unread_bytes -= msg->N_bytes;
} else {
unread_bytes = 0;
}
}
void write(unique_byte_buffer_t msg) { queue.push(std::move(msg)); }
srslte::error_type<unique_byte_buffer_t> try_write(unique_byte_buffer_t&& msg) srslte::error_type<unique_byte_buffer_t> try_write(unique_byte_buffer_t&& msg)
{ {
return queue.try_push(std::move(msg)); return queue.try_push(std::move(msg));
} }
unique_byte_buffer_t read() { return queue.wait_pop(); } unique_byte_buffer_t read() { return queue.pop_blocking(); }
bool try_read(unique_byte_buffer_t* msg) { return queue.try_pop(msg); } bool try_read(unique_byte_buffer_t* msg) { return queue.try_pop(*msg); }
void resize(uint32_t capacity) { queue.resize(capacity); } void resize(uint32_t capacity) { queue.set_size(capacity); }
uint32_t size() { return (uint32_t)queue.size(); } uint32_t size() { return (uint32_t)queue.size(); }
uint32_t size_bytes() { return unread_bytes; } uint32_t size_bytes() { return unread_bytes; }
uint32_t size_tail_bytes() uint32_t size_tail_bytes()
{ {
if (!queue.empty()) { uint32_t size_next = 0;
const unique_byte_buffer_t& m = queue.front(); queue.try_call_on_front([&size_next](const unique_byte_buffer_t& front_val) {
if (m.get()) { if (front_val != nullptr) {
return m->N_bytes; size_next += front_val->N_bytes;
} }
} });
return 0; return size_next;
} }
// This is a hack to reset N_bytes counter when queue is corrupted (see line 89) // This is a hack to reset N_bytes counter when queue is corrupted (see line 89)
@ -85,8 +77,19 @@ public:
bool is_full() { return queue.full(); } bool is_full() { return queue.full(); }
private: private:
block_queue<unique_byte_buffer_t> queue; struct push_callback {
uint32_t unread_bytes = 0; explicit push_callback(uint32_t& unread_bytes_) : unread_bytes(&unread_bytes_) {}
void operator()(const unique_byte_buffer_t& msg) { *unread_bytes += msg->N_bytes; }
uint32_t* unread_bytes;
};
struct pop_callback {
explicit pop_callback(uint32_t& unread_bytes_) : unread_bytes(&unread_bytes_) {}
void operator()(const unique_byte_buffer_t& msg) { *unread_bytes -= std::min(msg->N_bytes, *unread_bytes); }
uint32_t* unread_bytes;
};
dyn_blocking_queue<unique_byte_buffer_t, push_callback, pop_callback> queue;
uint32_t unread_bytes = 0;
}; };
} // namespace srslte } // namespace srslte

@ -22,8 +22,9 @@
#ifndef SRSLTE_GTPU_H #ifndef SRSLTE_GTPU_H
#define SRSLTE_GTPU_H #define SRSLTE_GTPU_H
#include "srslte/common/byte_buffer.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/logmap.h" #include "srslte/srslog/srslog.h"
#include <stdint.h> #include <stdint.h>
namespace srslte { namespace srslte {
@ -79,9 +80,9 @@ struct gtpu_header_t {
std::vector<uint8_t> ext_buffer; std::vector<uint8_t> ext_buffer;
}; };
bool gtpu_read_header(srslte::byte_buffer_t* pdu, gtpu_header_t* header, srslog::basic_logger& logger); bool gtpu_read_header(srslte::byte_buffer_t* pdu, gtpu_header_t* header, srslog::basic_logger& logger);
bool gtpu_write_header(gtpu_header_t* header, srslte::byte_buffer_t* pdu, srslog::basic_logger& logger); bool gtpu_write_header(gtpu_header_t* header, srslte::byte_buffer_t* pdu, srslog::basic_logger& logger);
std::string gtpu_ntoa(uint32_t addr); void gtpu_ntoa(fmt::memory_buffer& buffer, uint32_t addr);
inline bool gtpu_supported_flags_check(gtpu_header_t* header, srslog::basic_logger& logger) inline bool gtpu_supported_flags_check(gtpu_header_t* header, srslog::basic_logger& logger)
{ {

@ -23,7 +23,6 @@
#define SRSLTE_PDCP_H #define SRSLTE_PDCP_H
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/interfaces/ue_pdcp_interfaces.h"
#include "srslte/upper/pdcp_entity_lte.h" #include "srslte/upper/pdcp_entity_lte.h"
@ -68,8 +67,8 @@ public:
void write_pdu_bcch_bch(unique_byte_buffer_t sdu) override; void write_pdu_bcch_bch(unique_byte_buffer_t sdu) override;
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override; void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override;
void write_pdu_pcch(unique_byte_buffer_t sdu) override; void write_pdu_pcch(unique_byte_buffer_t sdu) override;
void notify_delivery(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) override; void notify_delivery(uint32_t lcid, const pdcp_sn_vector_t& pdcp_sns) override;
void notify_failure(uint32_t lcid, const std::vector<uint32_t>& pdcp_sn) override; void notify_failure(uint32_t lcid, const pdcp_sn_vector_t& pdcp_sns) override;
// eNB-only methods // eNB-only methods
std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint32_t lcid); std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint32_t lcid);

@ -26,7 +26,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/logmap.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
@ -121,12 +120,12 @@ public:
virtual void write_sdu(unique_byte_buffer_t sdu, int sn = -1) = 0; virtual void write_sdu(unique_byte_buffer_t sdu, int sn = -1) = 0;
// RLC interface // RLC interface
virtual void write_pdu(unique_byte_buffer_t pdu) = 0; virtual void write_pdu(unique_byte_buffer_t pdu) = 0;
virtual void notify_delivery(const std::vector<uint32_t>& pdcp_sns) = 0; virtual void notify_delivery(const pdcp_sn_vector_t& pdcp_sns) = 0;
virtual void notify_failure(const std::vector<uint32_t>& pdcp_sns) = 0; virtual void notify_failure(const pdcp_sn_vector_t& pdcp_sns) = 0;
virtual void get_bearer_state(pdcp_lte_state_t* state) = 0; virtual void get_bearer_state(pdcp_lte_state_t* state) = 0;
virtual void set_bearer_state(const pdcp_lte_state_t& state) = 0; virtual void set_bearer_state(const pdcp_lte_state_t& state, bool set_fmc) = 0;
virtual std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() = 0; virtual std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() = 0;

@ -25,7 +25,6 @@
#include "srslte/adt/circular_array.h" #include "srslte/adt/circular_array.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/interfaces/ue_rrc_interfaces.h"
@ -57,10 +56,10 @@ public:
// Getter for the number of discard timers. Used for debugging. // Getter for the number of discard timers. Used for debugging.
size_t nof_discard_timers() const; size_t nof_discard_timers() const;
bool add_sdu(uint32_t sn, bool add_sdu(uint32_t sn,
const srslte::unique_byte_buffer_t& sdu, const srslte::unique_byte_buffer_t& sdu,
uint32_t discard_timeout, uint32_t discard_timeout,
const std::function<void(uint32_t)>& callback); srslte::move_callback<void(uint32_t)> callback);
unique_byte_buffer_t& operator[](uint32_t sn) unique_byte_buffer_t& operator[](uint32_t sn)
{ {
@ -129,8 +128,8 @@ public:
// RLC interface // RLC interface
void write_pdu(unique_byte_buffer_t pdu) override; void write_pdu(unique_byte_buffer_t pdu) override;
void notify_failure(const std::vector<uint32_t>& pdcp_sns) override; void notify_failure(const pdcp_sn_vector_t& pdcp_sns) override;
void notify_delivery(const std::vector<uint32_t>& pdcp_sns) override; void notify_delivery(const pdcp_sn_vector_t& pdcp_sns) override;
// Config helpers // Config helpers
bool check_valid_config(); bool check_valid_config();
@ -147,7 +146,7 @@ public:
// Internal state getters/setters // Internal state getters/setters
void get_bearer_state(pdcp_lte_state_t* state) override; void get_bearer_state(pdcp_lte_state_t* state) override;
void set_bearer_state(const pdcp_lte_state_t& state) override; void set_bearer_state(const pdcp_lte_state_t& state, bool set_fmc) override;
// Metrics helpers // Metrics helpers
pdcp_bearer_metrics_t get_metrics() override; pdcp_bearer_metrics_t get_metrics() override;
@ -175,9 +174,31 @@ private:
// Discard callback (discardTimer) // Discard callback (discardTimer)
class discard_callback; class discard_callback;
// TX Queue // Tx info queue
uint32_t maximum_allocated_sns_window = 2048; uint32_t maximum_allocated_sns_window = 2048;
std::unique_ptr<undelivered_sdus_queue> undelivered_sdus; std::unique_ptr<undelivered_sdus_queue> undelivered_sdus;
// Rx info queue
uint32_t fmc = 0;
uint32_t largest_rx_count = 0;
std::vector<uint32_t> rx_counts_info; // Keeps the RX_COUNT for generation of the stauts report
void update_rx_counts_queue(uint32_t rx_count);
/*
* Helper function to see if an SN is larger
*/
bool is_sn_larger(uint32_t sn1, uint32_t sn2)
{
int32_t diff = sn2 - sn1;
uint32_t nof_sns = 1u << cfg.sn_len;
if (diff > (int32_t)(nof_sns / 2)) {
return false;
}
if (diff <= 0 && diff > -((int32_t)(nof_sns / 2))) {
return false;
}
return true;
}
}; };
// Discard callback (discardTimer) // Discard callback (discardTimer)

@ -26,7 +26,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
@ -60,8 +59,8 @@ public:
// RLC interface // RLC interface
void write_pdu(unique_byte_buffer_t pdu) final; void write_pdu(unique_byte_buffer_t pdu) final;
void notify_delivery(const std::vector<uint32_t>& tx_count) final; void notify_delivery(const pdcp_sn_vector_t& pdcp_sns) final;
void notify_failure(const std::vector<uint32_t>& tx_count) final; void notify_failure(const pdcp_sn_vector_t& pdcp_sns) final;
// State variable setters (should be used only for testing) // State variable setters (should be used only for testing)
void set_tx_next(uint32_t tx_next_) { tx_next = tx_next_; } void set_tx_next(uint32_t tx_next_) { tx_next = tx_next_; }
@ -70,7 +69,7 @@ public:
void set_rx_reord(uint32_t rx_reord_) { rx_reord = rx_reord_; } void set_rx_reord(uint32_t rx_reord_) { rx_reord = rx_reord_; }
void get_bearer_state(pdcp_lte_state_t* state) override; void get_bearer_state(pdcp_lte_state_t* state) override;
void set_bearer_state(const pdcp_lte_state_t& state) override; void set_bearer_state(const pdcp_lte_state_t& state, bool set_fmc) override;
void send_status_report() override {} void send_status_report() override {}
pdcp_bearer_metrics_t get_metrics() override; pdcp_bearer_metrics_t get_metrics() override;

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/interfaces/ue_pdcp_interfaces.h"
#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srslte/interfaces/ue_rlc_interfaces.h"

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
#include <map> #include <map>

@ -26,9 +26,9 @@
#include "srslte/adt/circular_array.h" #include "srslte/adt/circular_array.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/common/timeout.h" #include "srslte/common/timeout.h"
#include "srslte/interfaces/pdcp_interface_types.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_am_base.h" #include "srslte/upper/rlc_am_base.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
@ -51,12 +51,12 @@ struct rlc_amd_rx_pdu_segments_t {
}; };
struct rlc_amd_tx_pdu_t { struct rlc_amd_tx_pdu_t {
rlc_amd_pdu_header_t header; rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
std::vector<uint32_t> pdcp_sns; pdcp_sn_vector_t pdcp_sns;
uint32_t retx_count; uint32_t retx_count;
uint32_t rlc_sn; uint32_t rlc_sn;
bool is_acked; bool is_acked;
}; };
struct rlc_amd_retx_t { struct rlc_amd_retx_t {
@ -354,11 +354,11 @@ private:
// Tx windows // Tx windows
rlc_ringbuffer_t<rlc_amd_tx_pdu_t> tx_window; rlc_ringbuffer_t<rlc_amd_tx_pdu_t> tx_window;
pdu_retx_queue retx_queue; pdu_retx_queue retx_queue;
std::vector<uint32_t> notify_info_vec; pdcp_sn_vector_t notify_info_vec;
// Mutexes // Mutexes
pthread_mutex_t mutex; std::mutex mutex;
}; };
// Receiver sub-class // Receiver sub-class
@ -420,8 +420,8 @@ private:
uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs. uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
// Mutexes // Mutex to protect members
pthread_mutex_t mutex; std::mutex mutex;
// Rx windows // Rx windows
rlc_ringbuffer_t<rlc_amd_rx_pdu_t> rx_window; rlc_ringbuffer_t<rlc_amd_rx_pdu_t> rx_window;
@ -477,8 +477,7 @@ uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_pdu_segment(uint8_t* payload);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_sdu_info_t>& info_queue); std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_sdu_info_t>& info_queue);
std::string rlc_am_status_pdu_to_string(rlc_status_pdu_t* status); void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);
std::string rlc_amd_pdu_header_to_string(const rlc_amd_pdu_header_t& header);
bool rlc_am_start_aligned(const uint8_t fi); bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(const uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi); bool rlc_am_is_unaligned(const uint8_t fi);

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_am_base.h" #include "srslte/upper/rlc_am_base.h"
#include <map> #include <map>

@ -22,8 +22,7 @@
#ifndef SRSLTE_RLC_COMMON_H #ifndef SRSLTE_RLC_COMMON_H
#define SRSLTE_RLC_COMMON_H #define SRSLTE_RLC_COMMON_H
#include "srslte/common/block_queue.h" #include "srslte/adt/circular_buffer.h"
#include "srslte/common/logmap.h"
#include "srslte/interfaces/rlc_interface_types.h" #include "srslte/interfaces/rlc_interface_types.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include <stdlib.h> #include <stdlib.h>
@ -37,6 +36,7 @@ namespace srslte {
#define RLC_AM_WINDOW_SIZE 512 #define RLC_AM_WINDOW_SIZE 512
#define RLC_MAX_SDU_SIZE ((1 << 11) - 1) // Length of LI field is 11bits #define RLC_MAX_SDU_SIZE ((1 << 11) - 1) // Length of LI field is 11bits
#define RLC_AM_MIN_DATA_PDU_SIZE (3) // AMD PDU with 10 bit SN (length of LI field is 11 bits) (No LI)
typedef enum { typedef enum {
RLC_FI_FIELD_START_AND_END_ALIGNED = 0, RLC_FI_FIELD_START_AND_END_ALIGNED = 0,
@ -228,13 +228,13 @@ public:
} }
pdu_t p; pdu_t p;
// Do not block // Do not block
while (rx_pdu_resume_queue.try_pop(&p)) { while (rx_pdu_resume_queue.try_pop(p)) {
write_pdu(p.payload, p.nof_bytes); write_pdu(p.payload, p.nof_bytes);
free(p.payload); free(p.payload);
} }
unique_byte_buffer_t s; unique_byte_buffer_t s;
while (tx_sdu_resume_queue.try_pop(&s)) { while (tx_sdu_resume_queue.try_pop(s)) {
write_sdu(std::move(s)); write_sdu(std::move(s));
} }
suspended = false; suspended = false;
@ -312,8 +312,8 @@ private:
uint32_t nof_bytes; uint32_t nof_bytes;
} pdu_t; } pdu_t;
block_queue<pdu_t> rx_pdu_resume_queue; static_blocking_queue<pdu_t, 256> rx_pdu_resume_queue;
block_queue<unique_byte_buffer_t> tx_sdu_resume_queue{256}; static_blocking_queue<unique_byte_buffer_t, 256> tx_sdu_resume_queue;
}; };
} // namespace srslte } // namespace srslte

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"

@ -25,7 +25,6 @@
#include "srslte/adt/accumulators.h" #include "srslte/adt/accumulators.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/task_scheduler.h" #include "srslte/common/task_scheduler.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_um_base.h" #include "srslte/upper/rlc_um_base.h"
#include <map> #include <map>

@ -24,7 +24,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/byte_buffer_queue.h"
#include "srslte/upper/rlc_um_base.h" #include "srslte/upper/rlc_um_base.h"

@ -28,9 +28,6 @@ set(SOURCES arch_select.cc
crash_handler.cc crash_handler.cc
gen_mch_tables.c gen_mch_tables.c
liblte_security.cc liblte_security.cc
log_filter.cc
logmap.cc
logger_srslog_wrapper.cc
mac_pcap.cc mac_pcap.cc
mac_pcap_base.cc mac_pcap_base.cc
nas_pcap.cc nas_pcap.cc

@ -1,307 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <cstdlib>
#include <inttypes.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string.h>
#include <sys/time.h>
#include "srslte/common/log_filter.h"
#include "srslte/srslog/srslog.h"
namespace srslte {
#define CHARS_FOR_HEX_DUMP(size) \
(3 * size + size / 16 * 20) // 3 chars per byte, plus 20 per line for position and newline)
log_filter::log_filter() : log()
{
do_tti = false;
time_src = NULL;
time_format = TIME;
logger_h = NULL;
}
/// Creates a log channel that writes to stdout.
static srslog::log_channel* create_or_get_default_logger()
{
srslog::sink* s = srslog::create_stdout_sink();
if (!s) {
s = srslog::find_sink("stdout");
}
srslog::log_channel* log = srslog::create_log_channel("log_filter_default", *s);
if (!log) {
log = srslog::find_log_channel("log_filter_default");
}
srslog::init();
return log;
}
log_filter::log_filter(std::string layer) : log()
{
do_tti = false;
time_src = NULL;
time_format = TIME;
default_logger = std::unique_ptr<srslog_wrapper>(new srslog_wrapper(*create_or_get_default_logger()));
init(layer, default_logger.get(), do_tti);
}
log_filter::log_filter(std::string layer, logger* logger_, bool tti) : log()
{
do_tti = false;
time_src = NULL;
time_format = TIME;
if (!logger_) {
default_logger = std::unique_ptr<srslog_wrapper>(new srslog_wrapper(*create_or_get_default_logger()));
logger_ = default_logger.get();
}
init(std::move(layer), logger_, tti);
}
void log_filter::init(std::string layer, logger* logger_, bool tti)
{
// strip trailing white spaces
size_t last_char_pos = layer.find_last_not_of(' ');
if (last_char_pos != layer.size() - 1) {
layer.erase(last_char_pos + 1, layer.size());
}
service_name = std::move(layer);
logger_h = logger_;
do_tti = tti;
}
void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
char* msg,
const uint8_t* hex,
int size,
bool long_msg)
{
char buffer_tti[16] = {};
if (logger_h) {
logger::unique_log_str_t log_str = nullptr;
if (long_msg || hex) {
// For long messages, dynamically allocate a new log_str with enough size outside the pool.
uint32_t log_str_msg_len = sizeof(buffer_tti) + 20 + strlen(msg) + CHARS_FOR_HEX_DUMP(size);
log_str = logger::unique_log_str_t(new logger::log_str(nullptr, log_str_msg_len), logger::log_str_deleter());
} else {
log_str = logger_h->allocate_unique_log_str();
}
if (log_str) {
if (do_tti) {
get_tti_str(tti, buffer_tti, sizeof(buffer_tti));
}
// Trim away a newline character at the end of the message.
if (msg[strlen(msg) - 1] == '\n') {
msg[strlen(msg) - 1] = '\0';
}
snprintf(log_str->str(),
log_str->get_buffer_size(),
"[%-4s] %s %s%s%s%s",
get_service_name().c_str(),
log_level_text_short[level],
do_tti ? buffer_tti : "",
add_string_en ? add_string_val.c_str() : "",
msg,
(hex_limit > 0 && hex && size > 0) ? hex_string(hex, size).c_str() : "");
logger_h->log(std::move(log_str));
} else {
logger_h->log_char("Error in Log: Not enough buffers in pool\n");
}
}
}
#define all_log_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg); \
va_end(args); \
} \
} while (0)
#define all_log_hex_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg, hex, size); \
va_end(args); \
} \
} while (0)
void log_filter::error(const char* message, ...)
{
all_log_expand(LOG_LEVEL_ERROR);
}
void log_filter::warning(const char* message, ...)
{
all_log_expand(LOG_LEVEL_WARNING);
}
void log_filter::info(const char* message, ...)
{
all_log_expand(LOG_LEVEL_INFO);
}
void log_filter::info_long(const char* message, ...)
{
if (level >= LOG_LEVEL_INFO) {
char* args_msg = NULL;
va_list args;
va_start(args, message);
if (vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg, nullptr, strlen(args_msg), true);
va_end(args);
free(args_msg);
}
}
void log_filter::debug(const char* message, ...)
{
all_log_expand(LOG_LEVEL_DEBUG);
}
void log_filter::debug_long(const char* message, ...)
{
if (level >= LOG_LEVEL_DEBUG) {
char* args_msg = NULL;
va_list args;
va_start(args, message);
if (vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg, nullptr, strlen(args_msg), true);
va_end(args);
free(args_msg);
}
}
void log_filter::error_hex(const uint8_t* hex, int size, const char* message, ...)
{
all_log_hex_expand(LOG_LEVEL_ERROR);
}
void log_filter::warning_hex(const uint8_t* hex, int size, const char* message, ...)
{
all_log_hex_expand(LOG_LEVEL_WARNING);
}
void log_filter::info_hex(const uint8_t* hex, int size, const char* message, ...)
{
all_log_hex_expand(LOG_LEVEL_INFO);
}
void log_filter::debug_hex(const uint8_t* hex, int size, const char* message, ...)
{
all_log_hex_expand(LOG_LEVEL_DEBUG);
}
void log_filter::set_time_src(time_itf* source, time_format_t format)
{
this->time_src = source;
this->time_format = format;
}
void log_filter::get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len)
{
snprintf(buffer, buffer_len, "[%5d] ", tti_);
}
void log_filter::now_time(char* buffer, const uint32_t buffer_len)
{
timeval rawtime = {};
tm timeinfo = {};
char us[16];
srslte_timestamp_t now;
uint64_t usec_epoch;
if (buffer_len < 16) {
fprintf(stderr, "Error buffer provided for time too small\n");
return;
}
if (!time_src) {
gettimeofday(&rawtime, nullptr);
gmtime_r(&rawtime.tv_sec, &timeinfo);
if (time_format == TIME) {
strftime(buffer, buffer_len, "%H:%M:%S.", &timeinfo);
snprintf(us, 16, "%06ld", rawtime.tv_usec);
uint32_t dest_len = (uint32_t)strlen(buffer);
strncat(buffer, us, buffer_len - dest_len - 1);
} else {
usec_epoch = rawtime.tv_sec * 1000000UL + rawtime.tv_usec;
snprintf(buffer, buffer_len, "%" PRIu64, usec_epoch);
}
} else {
now = time_src->get_time();
if (time_format == TIME) {
snprintf(buffer, buffer_len, "%ld:%06u", now.full_secs, (uint32_t)(now.frac_secs * 1e6));
} else {
usec_epoch = now.full_secs * 1000000UL + (uint64_t)(now.frac_secs * 1e6);
snprintf(buffer, buffer_len, "%" PRIu64, usec_epoch);
}
}
}
std::string log_filter::hex_string(const uint8_t* hex, int size)
{
std::stringstream ss;
int c = 0;
ss << '\n' << std::hex << std::setfill('0');
if (hex_limit >= 0) {
size = (size > hex_limit) ? hex_limit : size;
}
while (c < size) {
ss << " " << std::setw(4) << static_cast<unsigned>(c) << ": ";
int tmp = (size - c < 16) ? size - c : 16;
for (int i = 0; i < tmp; i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[c++]) << " ";
}
if (c != size) {
ss << "\n";
}
}
return ss.str();
}
} // namespace srslte

@ -1,30 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/logger_srslog_wrapper.h"
#include "srslte/srslog/log_channel.h"
using namespace srslte;
void srslog_wrapper::log(unique_log_str_t msg)
{
chan("%s", msg->str());
}

@ -1,129 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/logmap.h"
#include "srslte/common/log_filter.h"
#include "srslte/srslog/srslog.h"
using namespace srslte;
log_ref::log_ref(const char* name)
{
ptr_ = srslte::logmap::get(name).ptr_;
}
/// Creates a log channel that writes to stdout.
static srslog::log_channel* create_or_get_default_logger()
{
srslog::sink* s = srslog::create_stdout_sink();
if (!s) {
s = srslog::find_sink("stdout");
}
srslog::log_channel* log = srslog::create_log_channel("logmap_default", *s);
if (!log) {
log = srslog::find_log_channel("logmap_default");
}
srslog::init();
return log;
}
logmap::logmap()
{
stdout_channel = std::unique_ptr<srslog_wrapper>(new srslog_wrapper(*create_or_get_default_logger()));
default_logger = stdout_channel.get();
}
// Access to log map by servicename. If servicename does not exist, create a new log_filter with default cfg
// Access to the map is protected by a mutex
log_ref SRSLTE_EXPORT logmap::get(std::string servicename)
{
logmap* pool = get_instance();
// strip trailing white spaces
size_t last_char_pos = servicename.find_last_not_of(' ');
if (last_char_pos != servicename.size() - 1) {
servicename.erase(last_char_pos + 1, servicename.size());
}
return pool->get_impl(std::move(servicename));
}
// register manually created log
void SRSLTE_EXPORT logmap::register_log(std::unique_ptr<log> log_ptr)
{
logmap* pool = get_instance();
std::lock_guard<std::mutex> lock(pool->mutex);
if (log_ptr != nullptr) {
pool->log_map[log_ptr->get_service_name()] = std::move(log_ptr);
}
}
std::unique_ptr<srslte::log> SRSLTE_EXPORT logmap::deregister_log(const std::string& servicename)
{
logmap* pool = get_instance();
std::unique_ptr<srslte::log> ret;
std::lock_guard<std::mutex> lock(pool->mutex);
auto it = pool->log_map.find(servicename);
if (it != pool->log_map.end()) {
ret = std::move(it->second);
pool->log_map.erase(it);
}
return ret;
}
// set default logger
void SRSLTE_EXPORT logmap::set_default_logger(logger* logger_)
{
logmap* pool = get_instance();
std::lock_guard<std::mutex> lock(pool->mutex);
pool->default_logger = logger_;
}
// set default log level
void SRSLTE_EXPORT logmap::set_default_log_level(LOG_LEVEL_ENUM l)
{
logmap* pool = get_instance();
std::lock_guard<std::mutex> lock(pool->mutex);
pool->default_log_level = l;
}
// set default hex limit
void SRSLTE_EXPORT logmap::set_default_hex_limit(int hex_limit)
{
logmap* pool = get_instance();
std::lock_guard<std::mutex> lock(pool->mutex);
pool->default_hex_limit = hex_limit;
}
log_ref logmap::get_impl(std::string servicename)
{
std::lock_guard<std::mutex> lock(mutex);
auto it = log_map.find(servicename);
if (it == log_map.end()) {
// create a new logger with default cfg
std::unique_ptr<log_filter> filter(new log_filter{std::move(servicename), default_logger});
filter->set_level(default_log_level);
filter->set_hex_limit(default_hex_limit);
auto ret = log_map.insert(std::make_pair(filter->get_service_name(), std::move(filter)));
return log_ref{&ret.first->second};
}
return log_ref{&it->second};
}

@ -20,6 +20,7 @@
*/ */
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
#include "srslte/common/standard_streams.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
namespace srslte { namespace srslte {
@ -67,7 +68,7 @@ uint32_t mac_pcap::close()
// tell writer thread to stop // tell writer thread to stop
running = false; running = false;
pcap_pdu_t pdu = {}; pcap_pdu_t pdu = {};
queue.push(std::move(pdu)); queue.push_blocking(std::move(pdu));
} }
wait_thread_finish(); wait_thread_finish();

@ -46,7 +46,7 @@ void mac_pcap_base::run_thread()
{ {
// blocking write until stopped // blocking write until stopped
while (running) { while (running) {
pcap_pdu_t pdu = queue.wait_pop(); pcap_pdu_t pdu = queue.pop_blocking();
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
write_pdu(pdu); write_pdu(pdu);
@ -56,7 +56,7 @@ void mac_pcap_base::run_thread()
// write remainder of queue // write remainder of queue
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
pcap_pdu_t pdu = {}; pcap_pdu_t pdu = {};
while (queue.try_pop(&pdu)) { while (queue.try_pop(pdu)) {
write_pdu(pdu); write_pdu(pdu);
} }
} }
@ -93,7 +93,9 @@ void mac_pcap_base::pack_and_queue(uint8_t* payload,
// copy payload into PDU buffer // copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len); memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len; pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu)); if (not queue.try_push(std::move(pdu))) {
logger.error("Failed to push message to pcap writer queue");
}
} else { } else {
logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
} }
@ -128,7 +130,9 @@ void mac_pcap_base::pack_and_queue_nr(uint8_t* payload,
// copy payload into PDU buffer // copy payload into PDU buffer
memcpy(pdu.pdu->msg, payload, payload_len); memcpy(pdu.pdu->msg, payload, payload_len);
pdu.pdu->N_bytes = payload_len; pdu.pdu->N_bytes = payload_len;
queue.push(std::move(pdu)); if (not queue.try_push(std::move(pdu))) {
logger.error("Failed to push message to pcap writer queue");
}
} else { } else {
logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len);
} }

@ -80,7 +80,7 @@ uint32_t mac_pcap_net::close()
// tell writer thread to stop // tell writer thread to stop
running = false; running = false;
pcap_pdu_t pdu = {}; pcap_pdu_t pdu = {};
queue.push(std::move(pdu)); queue.push_blocking(std::move(pdu));
} }
wait_thread_finish(); wait_thread_finish();

@ -18,12 +18,11 @@
* and at http://www.gnu.org/licenses/. * and at http://www.gnu.org/licenses/.
* *
*/ */
#include <srslte/common/log_filter.h> #include "srslte/common/common.h"
#include <srslte/common/logger_srslog_wrapper.h> #include "srslte/common/thread_pool.h"
#include <srslte/common/thread_pool.h> #include "srslte/common/tti_sempahore.h"
#include <srslte/common/tti_sempahore.h> #include "srslte/phy/utils/random.h"
#include <srslte/phy/utils/random.h> #include "srslte/srslog/srslog.h"
#include <srslte/srslog/srslog.h>
class dummy_radio class dummy_radio
{ {

@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include "srslte/common/standard_streams.h"
#include "srslte/mac/pdu.h" #include "srslte/mac/pdu.h"
extern "C" { extern "C" {
@ -208,11 +209,10 @@ bool lcid_t::is_sdu() const
* SCH PDU * SCH PDU
*************************/ *************************/
std::string sch_pdu::to_string() void sch_pdu::to_string(fmt::memory_buffer& buffer)
{ {
std::stringstream ss; fmt::format_to(buffer, "{}", is_ul() ? "UL" : "DL");
ss << (is_ul() ? "UL " : "DL ") << pdu::to_string(); pdu::to_string(buffer);
return ss.str();
} }
void sch_pdu::parse_packet(uint8_t* ptr) void sch_pdu::parse_packet(uint8_t* ptr)
@ -906,19 +906,18 @@ void sch_subh::read_payload(uint8_t** ptr)
*ptr += nof_bytes; *ptr += nof_bytes;
} }
std::string sch_subh::to_string() void sch_subh::to_string(fmt::memory_buffer& buffer)
{ {
std::stringstream ss;
if (is_sdu()) { if (is_sdu()) {
ss << "LCID=" << lcid << " len=" << nof_bytes; fmt::format_to(buffer, "LCID={} len={}", lcid, nof_bytes);
} else if (type == SCH_SUBH_TYPE) { } else if (type == SCH_SUBH_TYPE) {
if (parent->is_ul()) { if (parent->is_ul()) {
switch ((ul_sch_lcid)lcid) { switch ((ul_sch_lcid)lcid) {
case ul_sch_lcid::CRNTI: case ul_sch_lcid::CRNTI:
ss << "CRNTI: rnti=0x" << std::hex << get_c_rnti() << std::dec; fmt::format_to(buffer, "CRNTI: rnti=0x{:x}", get_c_rnti());
break; break;
case ul_sch_lcid::PHR_REPORT: case ul_sch_lcid::PHR_REPORT:
ss << "PHR: ph=" << get_phr(); fmt::format_to(buffer, "PHR: ph={}", get_phr());
break; break;
case ul_sch_lcid::TRUNC_BSR: case ul_sch_lcid::TRUNC_BSR:
case ul_sch_lcid::SHORT_BSR: case ul_sch_lcid::SHORT_BSR:
@ -927,18 +926,18 @@ std::string sch_subh::to_string()
uint32_t buff_size_bytes[4] = {}; uint32_t buff_size_bytes[4] = {};
uint32_t lcg = get_bsr(buff_size_idx, buff_size_bytes); uint32_t lcg = get_bsr(buff_size_idx, buff_size_bytes);
if (ul_sch_ce_type() == ul_sch_lcid::LONG_BSR) { if (ul_sch_ce_type() == ul_sch_lcid::LONG_BSR) {
ss << "LBSR: b="; fmt::format_to(buffer, "LBSR: b=");
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
ss << buff_size_idx[i] << " "; fmt::format_to(buffer, "{} ", buff_size_idx[i]);
} }
} else if (ul_sch_ce_type() == ul_sch_lcid::SHORT_BSR) { } else if (ul_sch_ce_type() == ul_sch_lcid::SHORT_BSR) {
ss << "SBSR: lcg=" << lcg << " b=" << buff_size_idx[lcg]; fmt::format_to(buffer, "SBSR: lcg={} b={}", lcg, buff_size_idx[lcg]);
} else { } else {
ss << "TBSR: lcg=" << lcg << " b=" << buff_size_idx[lcg]; fmt::format_to(buffer, "TBSR: lcg={} b={}", lcg, buff_size_idx[lcg]);
} }
} break; } break;
case ul_sch_lcid::PADDING: case ul_sch_lcid::PADDING:
ss << "PAD: len=" << get_payload_size(); fmt::format_to(buffer, "PAD: len={}", get_payload_size());
break; break;
default: default:
// do nothing // do nothing
@ -947,20 +946,20 @@ std::string sch_subh::to_string()
} else { } else {
switch ((dl_sch_lcid)lcid) { switch ((dl_sch_lcid)lcid) {
case dl_sch_lcid::CON_RES_ID: case dl_sch_lcid::CON_RES_ID:
ss << "CON_RES: id=0x" << std::hex << get_con_res_id() << std::dec; fmt::format_to(buffer, "CON_RES: id=0x{:x}", get_con_res_id());
break; break;
case dl_sch_lcid::TA_CMD: case dl_sch_lcid::TA_CMD:
ss << "TA: ta=" << std::to_string(get_ta_cmd()); fmt::format_to(buffer, "TA: ta={}", get_ta_cmd());
break; break;
case dl_sch_lcid::SCELL_ACTIVATION_4_OCTET: case dl_sch_lcid::SCELL_ACTIVATION_4_OCTET:
case dl_sch_lcid::SCELL_ACTIVATION: case dl_sch_lcid::SCELL_ACTIVATION:
ss << "SCELL_ACT"; fmt::format_to(buffer, "SCELL_ACT");
break; break;
case dl_sch_lcid::DRX_CMD: case dl_sch_lcid::DRX_CMD:
ss << "DRX"; fmt::format_to(buffer, "DRX");
break; break;
case dl_sch_lcid::PADDING: case dl_sch_lcid::PADDING:
ss << "PAD: len=" << get_payload_size(); fmt::format_to(buffer, "PAD: len={}", get_payload_size());
break; break;
default: default:
break; break;
@ -969,16 +968,15 @@ std::string sch_subh::to_string()
} else if (type == MCH_SUBH_TYPE) { } else if (type == MCH_SUBH_TYPE) {
switch ((mch_lcid)lcid) { switch ((mch_lcid)lcid) {
case mch_lcid::MCH_SCHED_INFO: case mch_lcid::MCH_SCHED_INFO:
ss << "MCH_SCHED_INFO"; fmt::format_to(buffer, "MCH_SCHED_INFO");
break; break;
case mch_lcid::PADDING: case mch_lcid::PADDING:
ss << "PAD: len=" << get_payload_size(); fmt::format_to(buffer, "PAD: len={}", get_payload_size());
break; break;
default: default:
break; break;
} }
} }
return ss.str();
} }
uint8_t sch_subh::buff_size_table(uint32_t buffer_size) uint8_t sch_subh::buff_size_table(uint32_t buffer_size)
@ -1009,11 +1007,11 @@ uint8_t sch_subh::phr_report_table(float phr_value)
return (uint8_t)floor(phr_value + 23); return (uint8_t)floor(phr_value + 23);
} }
std::string rar_pdu::to_string() void rar_pdu::to_string(fmt::memory_buffer& buffer)
{ {
std::string msg("MAC PDU for RAR: "); std::string msg("MAC PDU for RAR: ");
msg += pdu::to_string(); fmt::format_to(buffer, "MAC PDU for RAR: ");
return msg; pdu::to_string(buffer);
} }
rar_pdu::rar_pdu(uint32_t max_rars_, srslog::basic_logger& logger) : pdu(max_rars_, logger) rar_pdu::rar_pdu(uint32_t max_rars_, srslog::basic_logger& logger) : pdu(max_rars_, logger)
@ -1074,20 +1072,17 @@ bool rar_pdu::write_packet(uint8_t* ptr)
return true; return true;
} }
std::string rar_subh::to_string() void rar_subh::to_string(fmt::memory_buffer& buffer)
{ {
std::stringstream ss;
if (type == RAPID) { if (type == RAPID) {
ss << "RAPID: " << preamble << ", Temp C-RNTI: " << temp_rnti << ", TA: " << ta << ", UL Grant: "; fmt::format_to(buffer, "RAPID: {}, Temp C-RNTI: {}, TA: {}, UL Grant: ", preamble, temp_rnti, ta);
} else { } else {
ss << "Backoff Indicator: " << int32_t(((rar_pdu*)parent)->get_backoff()) << " "; fmt::format_to(buffer, "Backoff Indicator: {} ", int32_t(((rar_pdu*)parent)->get_backoff()));
} }
char tmp[16]; char tmp[16];
srslte_vec_sprint_hex(tmp, sizeof(tmp), grant, RAR_GRANT_LEN); srslte_vec_sprint_hex(tmp, sizeof(tmp), grant, RAR_GRANT_LEN);
ss << tmp; fmt::format_to(buffer, "{}", tmp);
return ss.str();
} }
void rar_subh::init() void rar_subh::init()

@ -67,7 +67,9 @@ void pdu_queue::push(const uint8_t* ptr, uint32_t len, channel_t channel)
pdu_t* pdu = (pdu_t*)ptr; pdu_t* pdu = (pdu_t*)ptr;
pdu->len = len; pdu->len = len;
pdu->channel = channel; pdu->channel = channel;
pdu_q.push(pdu); if (!pdu_q.try_push(pdu)) {
logger.warning("Error pushing pdu: queue is full");
}
} else { } else {
logger.warning("Error pushing pdu: ptr is empty"); logger.warning("Error pushing pdu: ptr is empty");
} }
@ -78,7 +80,7 @@ bool pdu_queue::process_pdus()
bool have_data = false; bool have_data = false;
uint32_t cnt = 0; uint32_t cnt = 0;
pdu_t* pdu; pdu_t* pdu;
while (pdu_q.try_pop(&pdu)) { while (pdu_q.try_pop(pdu)) {
if (callback) { if (callback) {
callback->process_pdu(pdu->ptr, pdu->len, pdu->channel); callback->process_pdu(pdu->ptr, pdu->len, pdu->channel);
} }
@ -95,7 +97,7 @@ bool pdu_queue::process_pdus()
void pdu_queue::reset() void pdu_queue::reset()
{ {
pdu_t* pdu; pdu_t* pdu;
while (pdu_q.try_pop(&pdu)) { while (pdu_q.try_pop(pdu)) {
// nop // nop
} }
} }

@ -439,8 +439,7 @@ int srslte_dmrs_sch_get_N_prb(const srslte_dmrs_sch_cfg_t* dmrs_cfg, const srslt
} }
// Get number of frequency domain resource elements used for DMRS // Get number of frequency domain resource elements used for DMRS
int nof_sc = SRSLTE_MIN(SRSLTE_NRE, int nof_sc = SRSLTE_DMRS_SCH_SC(grant->nof_dmrs_cdm_groups_without_data, dmrs_cfg->type);
grant->nof_dmrs_cdm_groups_without_data * (dmrs_cfg->type == srslte_dmrs_sch_type_1 ? 6 : 4));
// Get number of symbols used for DMRS // Get number of symbols used for DMRS
uint32_t symbols[SRSLTE_DMRS_SCH_MAX_SYMBOLS] = {}; uint32_t symbols[SRSLTE_DMRS_SCH_MAX_SYMBOLS] = {};

@ -23,6 +23,7 @@
#include "srslte/phy/fec/ldpc/base_graph.h" #include "srslte/phy/fec/ldpc/base_graph.h"
#include "srslte/phy/fec/turbo/turbodecoder_gen.h" #include "srslte/phy/fec/turbo/turbodecoder_gen.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include <strings.h> #include <strings.h>
/** /**
@ -40,8 +41,6 @@ const uint32_t tc_cb_sizes[SRSLTE_NOF_TC_CB_SIZES] = {
3904, 3968, 4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, 4800, 4864, 4928, 4992, 5056, 3904, 3968, 4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, 4800, 4864, 4928, 4992, 5056,
5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144}; 5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144};
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
/** /**
* @brief Calculates the number of code blocks and the total size * @brief Calculates the number of code blocks and the total size
* @param[in] B Transport block size including TB CRC * @param[in] B Transport block size including TB CRC
@ -55,7 +54,7 @@ static void cbsegm_cb_size(uint32_t B, uint32_t Z, uint32_t* C, uint32_t* B_prim
*C = 1; *C = 1;
*B_prime = B; *B_prime = B;
} else { } else {
*C = CEIL(B, (Z - 24U)); *C = SRSLTE_CEIL(B, (Z - 24U));
*B_prime = B + 24U * (*C); *B_prime = B + 24U * (*C);
} }
} }
@ -160,12 +159,12 @@ bool srslte_cbsegm_cbsize_isvalid(uint32_t size)
static int cbsegm_ldpc_select_ls(uint32_t Kp, uint32_t K_b, uint32_t* Z_c, uint8_t* i_ls) static int cbsegm_ldpc_select_ls(uint32_t Kp, uint32_t K_b, uint32_t* Z_c, uint8_t* i_ls)
{ {
// Early return if the minimum required lift size is too high // Early return if the minimum required lift size is too high
if (CEIL(Kp, K_b) > MAX_LIFTSIZE) { if (SRSLTE_CEIL(Kp, K_b) > MAX_LIFTSIZE) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Iterate from the minimum required lift size to the maximum value // Iterate from the minimum required lift size to the maximum value
for (uint16_t Z = CEIL(Kp, K_b); Z <= MAX_LIFTSIZE; Z++) { for (uint16_t Z = SRSLTE_CEIL(Kp, K_b); Z <= MAX_LIFTSIZE; Z++) {
// Get index for a selected lifting size // Get index for a selected lifting size
uint8_t i = get_ls_index(Z); uint8_t i = get_ls_index(Z);

@ -132,7 +132,7 @@ int get_code_params(srslte_polar_code_t* c, const uint16_t K, const uint16_t E,
} }
if (K + nPC >= E) { if (K + nPC >= E) {
ERROR(" Rate-matched codeword length (E) not supported, choose E > %d", K + nPC); ERROR(" Rate-matched codeword length (E=%d) not supported, choose E > %d", E, K + nPC);
return -1; return -1;
} }

@ -21,6 +21,7 @@
#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/csi.h"
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include <math.h> #include <math.h>
#define CSI_WIDEBAND_CSI_NOF_BITS 4 #define CSI_WIDEBAND_CSI_NOF_BITS 4
@ -91,9 +92,9 @@ static uint32_t csi_wideband_cri_ri_pmi_cqi_nof_bits(const srslte_csi_report_cfg
return 0; return 0;
} }
static int csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg, static uint32_t csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg,
const srslte_csi_report_value_t* value, const srslte_csi_report_value_t* value,
uint8_t* o_csi1) uint8_t* o_csi1)
{ {
// Compute number of bits for CRI // Compute number of bits for CRI
uint32_t nof_bits_cri = 0; uint32_t nof_bits_cri = 0;
@ -110,6 +111,46 @@ static int csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg
return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS; return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS;
} }
static uint32_t csi_wideband_cri_ri_pmi_cqi_unpack(const srslte_csi_report_cfg_t* cfg,
uint8_t* o_csi1,
srslte_csi_report_value_t* value)
{
// Compute number of bits for CRI
uint32_t nof_bits_cri = 0;
if (cfg->K_csi_rs > 0) {
nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs));
}
// Write wideband CQI
value->wideband_cri_ri_pmi_cqi.cqi = srslte_bit_pack(&o_csi1, CSI_WIDEBAND_CSI_NOF_BITS);
// Compute number of bits for CRI and write
value->cri = srslte_bit_pack(&o_csi1, nof_bits_cri);
return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS;
}
static uint32_t csi_none_nof_bits(const srslte_csi_report_cfg_t* cfg)
{
return cfg->K_csi_rs;
}
static uint32_t
csi_none_pack(const srslte_csi_report_cfg_t* cfg, const srslte_csi_report_value_t* value, uint8_t* o_csi1)
{
srslte_vec_u8_copy(o_csi1, (uint8_t*)value->none, cfg->K_csi_rs);
return cfg->K_csi_rs;
}
static uint32_t
csi_none_unpack(const srslte_csi_report_cfg_t* cfg, const uint8_t* o_csi1, srslte_csi_report_value_t* value)
{
srslte_vec_u8_copy((uint8_t*)value->none, o_csi1, cfg->K_csi_rs);
return cfg->K_csi_rs;
}
int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg,
uint32_t slot_idx, uint32_t slot_idx,
const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES], const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES],
@ -161,7 +202,7 @@ int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg,
return (int)count; return (int)count;
} }
int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports) int srslte_csi_part1_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports)
{ {
uint32_t count = 0; uint32_t count = 0;
@ -175,12 +216,28 @@ int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof
const srslte_csi_report_cfg_t* report = &report_list[i]; const srslte_csi_report_cfg_t* report = &report_list[i];
if (report->quantity && report->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { if (report->quantity && report->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report); count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report);
} else if (report->quantity == SRSLTE_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_nof_bits(report);
} }
} }
return (int)count; return (int)count;
} }
bool srslte_csi_has_part2(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports)
{
if (report_list == NULL || nof_reports == 0) {
return false;
}
for (uint32_t i = 0; i < nof_reports; i++) {
if (report_list[i].has_part2) {
return true;
}
}
return false;
}
int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg,
const srslte_csi_report_value_t* report_value, const srslte_csi_report_value_t* report_value,
uint32_t nof_reports, uint32_t nof_reports,
@ -193,7 +250,7 @@ int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg,
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
int n = srslte_csi_nof_bits(report_cfg, nof_reports); int n = srslte_csi_part1_nof_bits(report_cfg, nof_reports);
if (n > (int)max_o_csi1) { if (n > (int)max_o_csi1) {
ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n); ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n);
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -203,6 +260,42 @@ int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg,
if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]); count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else if (report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].freq_cfg,
report_cfg[i].quantity);
}
}
return (int)count;
}
int srslte_csi_part1_unpack(const srslte_csi_report_cfg_t* report_cfg,
uint32_t nof_reports,
uint8_t* o_csi1,
uint32_t max_o_csi1,
srslte_csi_report_value_t* report_value)
{
uint32_t count = 0;
if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
int n = srslte_csi_part1_nof_bits(report_cfg, nof_reports);
if (n > (int)max_o_csi1) {
ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n);
return SRSLTE_ERROR;
}
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else if (report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else { } else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented", ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].freq_cfg, report_cfg[i].freq_cfg,
@ -224,6 +317,10 @@ uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg,
if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
len = srslte_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi); len = srslte_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
} else if (report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_NONE) {
char tmp[20] = {};
srslte_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs);
len = srslte_print_check(str, str_len, len, ", csi=%s", tmp);
} }
} }
return len; return len;

@ -203,7 +203,7 @@ static void srslte_pdsch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count,
* As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2: * As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2:
* *
* +---+---+---+---+---+---+---+---+---+---+---+---+ * +---+---+---+---+---+---+---+---+---+---+---+---+
* | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | * | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 |
* +---+---+---+---+---+---+---+---+---+---+---+---+ * +---+---+---+---+---+---+---+---+---+---+---+---+
* -- k --> * -- k -->
* *

@ -183,6 +183,17 @@ int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* arg
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_pucch_nr_set_carrier(srslte_pucch_nr_t* q, const srslte_carrier_nr_t* carrier)
{
if (q == NULL || carrier == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
q->carrier = *carrier;
return SRSLTE_SUCCESS;
}
void srslte_pucch_nr_free(srslte_pucch_nr_t* q) void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
{ {
if (q == NULL) { if (q == NULL) {
@ -210,14 +221,13 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
} }
int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q, int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
srslte_pucch_nr_resource_t* resource, srslte_pucch_nr_resource_t* resource,
uint32_t m_cs, uint32_t m_cs,
cf_t* slot_symbols) cf_t* slot_symbols)
{ {
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) { if (cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -228,7 +238,7 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
uint32_t u = 0; uint32_t u = 0;
uint32_t v = 0; uint32_t v = 0;
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) { if (srslte_pucch_nr_group_sequence(&q->carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence"); ERROR("Error getting group sequence");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -237,8 +247,8 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
for (uint32_t l = 0; l < resource->nof_symbols; l++) { for (uint32_t l = 0; l < resource->nof_symbols; l++) {
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < if (srslte_pucch_nr_alpha_idx(
SRSLTE_SUCCESS) { &q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -250,7 +260,7 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
} }
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE]; cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Copy sequence in grid // Copy sequence in grid
srslte_vec_cf_copy(slot_symbols_ptr, r_uv, SRSLTE_NRE); srslte_vec_cf_copy(slot_symbols_ptr, r_uv, SRSLTE_NRE);
@ -260,7 +270,6 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
} }
int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q, int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
srslte_pucch_nr_resource_t* resource, srslte_pucch_nr_resource_t* resource,
@ -268,7 +277,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
const cf_t* slot_symbols, const cf_t* slot_symbols,
srslte_pucch_nr_measure_t* measure) srslte_pucch_nr_measure_t* measure)
{ {
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || measure == NULL) { if (cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || measure == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -279,7 +288,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
uint32_t u = 0; uint32_t u = 0;
uint32_t v = 0; uint32_t v = 0;
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) { if (srslte_pucch_nr_group_sequence(&q->carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence"); ERROR("Error getting group sequence");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -290,8 +299,8 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
for (uint32_t l = 0; l < resource->nof_symbols; l++) { for (uint32_t l = 0; l < resource->nof_symbols; l++) {
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < if (srslte_pucch_nr_alpha_idx(
SRSLTE_SUCCESS) { &q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -304,7 +313,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
const cf_t* slot_symbols_ptr = const cf_t* slot_symbols_ptr =
&slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE]; &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Measure EPRE and average // Measure EPRE and average
epre += srslte_vec_avg_power_cf(slot_symbols_ptr, SRSLTE_NRE) / resource->nof_symbols; epre += srslte_vec_avg_power_cf(slot_symbols_ptr, SRSLTE_NRE) / resource->nof_symbols;
@ -369,7 +378,6 @@ cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n_pucch, uin
} }
int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q, int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -377,7 +385,7 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
uint32_t nof_bits, uint32_t nof_bits,
cf_t* slot_symbols) cf_t* slot_symbols)
{ {
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || b == NULL || slot_symbols == NULL) { if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || b == NULL || slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -402,7 +410,7 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
// Get group sequence // Get group sequence
uint32_t u = 0; uint32_t u = 0;
uint32_t v = 0; uint32_t v = 0;
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) { if (srslte_pucch_nr_group_sequence(&q->carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence"); ERROR("Error getting group sequence");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -413,11 +421,11 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
uint32_t l_prime = resource->start_symbol_idx; uint32_t l_prime = resource->start_symbol_idx;
for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) { for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) {
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE]; cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) < if (srslte_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
SRSLTE_SUCCESS) { SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -448,7 +456,6 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
} }
int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q, int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -459,6 +466,11 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
{ {
uint32_t m_cs = 0; uint32_t m_cs = 0;
if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || chest_res == NULL || b == NULL ||
slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) { if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource"); ERROR("Invalid PUCCH format 1 resource");
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -475,7 +487,7 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
// Get group sequence // Get group sequence
uint32_t u = 0; uint32_t u = 0;
uint32_t v = 0; uint32_t v = 0;
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) { if (srslte_pucch_nr_group_sequence(&q->carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence"); ERROR("Error getting group sequence");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -486,8 +498,8 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
uint32_t l_prime = resource->start_symbol_idx; uint32_t l_prime = resource->start_symbol_idx;
for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) { for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) {
// Get start of the sequence in resource grid // Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE]; cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
cf_t* ce_ptr = &chest_res->ce[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE]; cf_t* ce_ptr = &chest_res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Equalise x = w(i) * d' * r_uv(n) // Equalise x = w(i) * d' * r_uv(n)
cf_t x[SRSLTE_NRE]; cf_t x[SRSLTE_NRE];
@ -495,8 +507,8 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
// Get Alpha index // Get Alpha index
uint32_t alpha_idx = 0; uint32_t alpha_idx = 0;
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < if (srslte_pucch_nr_alpha_idx(
SRSLTE_SUCCESS) { &q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -535,7 +547,7 @@ static uint32_t pucch_nr_format2_cinit(const srslte_carrier_nr_t* carri
{ {
uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->id; uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->id;
return ((uint32_t)uci_cfg->rnti << 15U) + n_id; return ((uint32_t)uci_cfg->pucch.rnti << 15U) + n_id;
} }
// Implements TS 38.211 section 6.3.2.5 PUCCH format 2 // Implements TS 38.211 section 6.3.2.5 PUCCH format 2
@ -639,7 +651,6 @@ static int pucch_nr_format2_decode(srslte_pucch_nr_t* q,
} }
int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q, int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -648,8 +659,8 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
cf_t* slot_symbols) cf_t* slot_symbols)
{ {
// Validate input pointers // Validate input pointers
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || uci_cfg == NULL || if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || uci_cfg == NULL || uci_value == NULL ||
uci_value == NULL || slot_symbols == NULL) { slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -662,7 +673,7 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
// Modulate PUCCH // Modulate PUCCH
switch (resource->format) { switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2: case SRSLTE_PUCCH_NR_FORMAT_2:
return pucch_nr_format2_encode(q, carrier, cfg, resource, uci_cfg, slot_symbols); return pucch_nr_format2_encode(q, &q->carrier, cfg, resource, uci_cfg, slot_symbols);
case SRSLTE_PUCCH_NR_FORMAT_3: case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4: case SRSLTE_PUCCH_NR_FORMAT_4:
ERROR("Not implemented"); ERROR("Not implemented");
@ -676,7 +687,6 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
} }
int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q, int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg, const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_slot_cfg_t* slot, const srslte_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource, const srslte_pucch_nr_resource_t* resource,
@ -686,8 +696,8 @@ int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
srslte_uci_value_nr_t* uci_value) srslte_uci_value_nr_t* uci_value)
{ {
// Validate input pointers // Validate input pointers
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || uci_cfg == NULL || if (q == NULL || cfg == NULL || slot == NULL || resource == NULL || uci_cfg == NULL || chest_res == NULL ||
chest_res == NULL || uci_value == NULL || slot_symbols == NULL) { uci_value == NULL || slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -695,7 +705,8 @@ int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
int8_t* llr = (int8_t*)q->b; int8_t* llr = (int8_t*)q->b;
switch (resource->format) { switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2: case SRSLTE_PUCCH_NR_FORMAT_2:
if (pucch_nr_format2_decode(q, carrier, cfg, resource, uci_cfg, chest_res, slot_symbols, llr) < SRSLTE_SUCCESS) { if (pucch_nr_format2_decode(q, &q->carrier, cfg, resource, uci_cfg, chest_res, slot_symbols, llr) <
SRSLTE_SUCCESS) {
ERROR("Demodulating PUCCH format 2"); ERROR("Demodulating PUCCH format 2");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -23,7 +23,9 @@
#include "srslte/phy/mimo/layermap.h" #include "srslte/phy/mimo/layermap.h"
#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/precoding.h"
#include "srslte/phy/modem/demod_soft.h" #include "srslte/phy/modem/demod_soft.h"
#include "srslte/phy/phch/csi.h"
#include "srslte/phy/phch/ra_nr.h" #include "srslte/phy/phch/ra_nr.h"
#include "srslte/phy/phch/uci_cfg.h"
int pusch_nr_init_common(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* args) int pusch_nr_init_common(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* args)
{ {
@ -37,6 +39,29 @@ int pusch_nr_init_common(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t* arg
} }
} }
if (srslte_uci_nr_init(&q->uci, &args->uci) < SRSLTE_SUCCESS) {
ERROR("Initialising UCI");
return SRSLTE_ERROR;
}
q->g_ulsch = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->g_ack = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->g_csi1 = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->g_csi2 = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
if (q->g_ack == NULL || q->g_csi1 == NULL || q->g_csi2 == NULL || q->g_ulsch == NULL) {
ERROR("Malloc");
return SRSLTE_ERROR;
}
q->pos_ulsch = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->pos_ack = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->pos_csi1 = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
q->pos_csi2 = srslte_vec_u32_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
if (q->pos_ack == NULL || q->pos_csi1 == NULL || q->pos_csi2 == NULL || q->pos_ulsch == NULL) {
ERROR("Malloc");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -68,7 +93,7 @@ int srslte_pusch_nr_init_gnb(srslte_pusch_nr_t* q, const srslte_pusch_nr_args_t*
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_sch_nr_init_rx(&q->sch, &args->sch)) { if (srslte_sch_nr_init_rx(&q->sch, &args->sch) < SRSLTE_SUCCESS) {
ERROR("Initialising SCH"); ERROR("Initialising SCH");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -155,6 +180,32 @@ void srslte_pusch_nr_free(srslte_pusch_nr_t* q)
return; return;
} }
if (q->g_ulsch != NULL) {
free(q->g_ulsch);
}
if (q->g_ack != NULL) {
free(q->g_ack);
}
if (q->g_csi1 != NULL) {
free(q->g_csi1);
}
if (q->g_csi2 != NULL) {
free(q->g_csi2);
}
if (q->pos_ulsch != NULL) {
free(q->pos_ulsch);
}
if (q->pos_ack != NULL) {
free(q->pos_ack);
}
if (q->pos_csi1 != NULL) {
free(q->pos_csi1);
}
if (q->pos_csi2 != NULL) {
free(q->pos_csi2);
}
for (uint32_t cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { for (uint32_t cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) {
if (q->b[cw]) { if (q->b[cw]) {
free(q->b[cw]); free(q->b[cw]);
@ -166,6 +217,7 @@ void srslte_pusch_nr_free(srslte_pusch_nr_t* q)
} }
srslte_sch_nr_free(&q->sch); srslte_sch_nr_free(&q->sch);
srslte_uci_nr_free(&q->uci);
for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) { for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) {
if (q->x[i]) { if (q->x[i]) {
@ -180,6 +232,8 @@ void srslte_pusch_nr_free(srslte_pusch_nr_t* q)
if (q->evm_buffer != NULL) { if (q->evm_buffer != NULL) {
srslte_evm_free(q->evm_buffer); srslte_evm_free(q->evm_buffer);
} }
SRSLTE_MEM_ZERO(q, srslte_pusch_nr_t, 1);
} }
/** /**
@ -424,11 +478,354 @@ pusch_nr_cinit(const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_nr_t* cf
return cinit; return cinit;
} }
static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q, static inline int pusch_nr_fill_uci_cfg(srslte_pusch_nr_t* q, const srslte_sch_cfg_nr_t* cfg)
const srslte_sch_cfg_nr_t* cfg, {
const srslte_sch_tb_t* tb, if (cfg->grant.nof_prb == 0) {
const uint8_t* data, ERROR("Invalid number of PRB (%d)", cfg->grant.nof_prb);
uint16_t rnti) return SRSLTE_ERROR;
}
// Initially, copy all fields
q->uci_cfg = cfg->uci;
// Reset UCI PUSCH configuration
SRSLTE_MEM_ZERO(&q->uci_cfg.pusch, srslte_uci_nr_pusch_cfg_t, 1);
// Get DMRS symbol indexes
uint32_t nof_dmrs_l = 0;
uint32_t dmrs_l[SRSLTE_DMRS_SCH_MAX_SYMBOLS] = {};
int n = srslte_dmrs_sch_get_symbols_idx(&cfg->dmrs, &cfg->grant, dmrs_l);
if (n < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
nof_dmrs_l = (uint32_t)n;
// Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS
// Starts at first OFDM symbol carrying DMRS
for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
// Set value and stop iterating
q->uci_cfg.pusch.l0 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Find OFDM symbol index of the first OFDM symbol that does not carry DMRS
// Starts at first OFDM symbol of the PUSCH transmission
for (uint32_t l = cfg->grant.S, dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
q->uci_cfg.pusch.l1 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Number of DMRS per PRB
uint32_t n_sc_dmrs = SRSLTE_DMRS_SCH_SC(cfg->grant.nof_dmrs_cdm_groups_without_data, cfg->dmrs.type);
// Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1
for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) {
// Skip if OFDM symbol is outside of the PUSCH transmission
if (l < cfg->grant.S || l >= (cfg->grant.S + cfg->grant.L)) {
q->uci_cfg.pusch.M_pusch_sc[l] = 0;
q->uci_cfg.pusch.M_uci_sc[l] = 0;
continue;
}
// OFDM symbol carries DMRS
if (l == dmrs_l[dmrs_l_idx]) {
// Calculate PUSCH RE candidates
q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * (SRSLTE_NRE - n_sc_dmrs);
// The Number of RE candidates for UCI are 0
q->uci_cfg.pusch.M_uci_sc[l] = 0;
// Advance DMRS symbol index
dmrs_l_idx++;
// Skip to next symbol
continue;
}
// Number of RE for Phase Tracking Reference Signals (PT-RS)
uint32_t M_ptrs_sc = 0; // Not implemented yet
// Number of RE given by the grant
q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * SRSLTE_NRE;
// Calculate the number of UCI candidates
q->uci_cfg.pusch.M_uci_sc[l] = q->uci_cfg.pusch.M_pusch_sc[l] - M_ptrs_sc;
}
// Generate SCH Transport block information
srslte_sch_nr_tb_info_t sch_tb_info = {};
if (srslte_sch_nr_fill_tb_info(&q->carrier, &cfg->sch_cfg, &cfg->grant.tb[0], &sch_tb_info) < SRSLTE_SUCCESS) {
ERROR("Generating TB info");
return SRSLTE_ERROR;
}
// Calculate the sum of codeblock sizes
for (uint32_t i = 0; i < sch_tb_info.C; i++) {
// Accumulate codeblock size if mask is enabled
q->uci_cfg.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0;
}
// Set other PUSCH parameters
q->uci_cfg.pusch.modulation = cfg->grant.tb[0].mod;
q->uci_cfg.pusch.nof_layers = cfg->grant.nof_layers;
q->uci_cfg.pusch.R = (float)cfg->grant.tb[0].R;
q->uci_cfg.pusch.alpha = cfg->scaling;
q->uci_cfg.pusch.beta_harq_ack_offset = cfg->beta_harq_ack_offset;
q->uci_cfg.pusch.beta_csi1_offset = cfg->beta_csi_part1_offset;
q->uci_cfg.pusch.nof_re = cfg->grant.tb[0].nof_re;
return SRSLTE_SUCCESS;
}
// Implements TS 38.212 6.2.7 Data and control multiplexing (for NR-PUSCH)
static int pusch_nr_gen_mux_uci(srslte_pusch_nr_t* q, const srslte_uci_cfg_nr_t* cfg)
{
// Decide whether UCI shall be multiplexed
q->uci_mux = (q->G_ack > 0 || q->G_csi1 > 0 || q->G_csi2 > 0);
// Check if UCI multiplexing is NOT required
if (!q->uci_mux) {
return SRSLTE_SUCCESS;
}
// Bit positions
uint32_t* pos_ulsch = q->pos_ulsch; // coded bits for UL-SCH
uint32_t* pos_ack = q->pos_ack; // coded bits for HARQ-ACK
uint32_t* pos_csi1 = q->pos_csi1; // coded bits for CSI part 1
uint32_t* pos_csi2 = q->pos_csi2; // coded bits for CSI part 2
// Key OFDM symbol indexes
uint32_t l1 =
cfg->pusch.l0; // First OFDM symbol that does not carry DMRS of the PUSCH, after the first DMRS symbol(s)
uint32_t l1_csi = cfg->pusch.l1; // OFDM symbol index of the first OFDM symbol that does not carry DMRS
// Number of UCI bits
uint32_t G_ack = q->G_ack;
uint32_t G_csi1 = q->G_csi1;
uint32_t G_csi2 = q->G_csi2;
// Other...
uint32_t Nl = cfg->pusch.nof_layers;
uint32_t Qm = srslte_mod_bits_x_symbol(cfg->pusch.modulation);
// if the number of HARQ-ACK information bits to be transmitted on PUSCH is 0, 1 or 2 bits
uint32_t G_ack_rvd = 0;
if (cfg->o_ack <= 2) {
// the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause
// 6.3.2.4.2.1, by setting O_ACK = 2 ;
G_ack_rvd = srslte_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, 2);
// Disable non reserved HARQ-ACK bits
G_ack = 0;
}
// Counters
uint32_t m_ack_count = 0;
uint32_t m_csi1_count = 0;
uint32_t m_csi2_count = 0;
uint32_t m_ulsch_count = 0;
uint32_t m_all_count = 0;
for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) {
// Skip if symbol has potential for data
if (cfg->pusch.M_pusch_sc[l] == 0) {
continue;
}
// Put UL-SCH only if this OFDM symbol has no potential for UCI
if (cfg->pusch.M_uci_sc[l] == 0) {
for (uint32_t i = 0; i < cfg->pusch.M_pusch_sc[l] * Qm * Nl; i++) {
pos_ulsch[m_ulsch_count++] = m_all_count++;
}
continue;
}
uint32_t M_ulsch_sc = cfg->pusch.M_pusch_sc[l];
uint32_t M_uci_sc = cfg->pusch.M_uci_sc[l];
uint32_t M_uci_rvd = 0;
// Compute HARQ-ACK bits multiplexing
uint32_t ack_d = 0;
uint32_t ack_m_re_count = 0;
if (l >= l1) {
if (cfg->o_ack <= 2 && m_ack_count < G_ack_rvd) {
ack_d = 1;
ack_m_re_count = M_ulsch_sc;
if (G_ack_rvd - m_ack_count < M_uci_sc * Nl * Qm) {
ack_d = (M_uci_sc * Nl * Qm) / (G_ack_rvd - m_ack_count);
ack_m_re_count = SRSLTE_CEIL(G_ack_rvd - m_ack_count, Nl * Qm);
}
M_uci_rvd = ack_m_re_count;
} else if (m_ack_count < G_ack) {
ack_d = 1;
ack_m_re_count = M_ulsch_sc;
if (G_ack - m_ack_count < M_uci_sc * Nl * Qm) {
ack_d = (M_uci_sc * Nl * Qm) / (G_ack - m_ack_count);
ack_m_re_count = SRSLTE_CEIL(G_ack - m_ack_count, Nl * Qm);
}
M_uci_sc -= ack_m_re_count;
}
}
// Compute CSI part 1 bits multiplexing
uint32_t csi1_d = 0;
uint32_t csi1_m_re_count = 0;
if (l >= l1_csi && M_uci_sc > M_uci_rvd && m_csi1_count < G_csi1) {
csi1_d = 1;
csi1_m_re_count = M_uci_sc - M_uci_rvd;
if (G_csi1 - m_csi1_count < (M_uci_sc - M_uci_rvd) * Nl * Qm) {
csi1_d = ((M_uci_sc - M_uci_rvd) * Nl * Qm) / (G_csi1 - m_csi1_count);
csi1_m_re_count = SRSLTE_CEIL(G_csi1 - m_csi1_count, Nl * Qm);
}
M_uci_sc -= csi1_m_re_count;
}
// Compute CSI part 2 bits multiplexing
uint32_t csi2_d = 0;
uint32_t csi2_m_re_count = 0;
if (l >= l1_csi && M_uci_sc > M_uci_rvd && m_csi2_count < G_csi2) {
csi2_d = 1;
csi2_m_re_count = M_uci_sc - M_uci_rvd;
if (G_csi2 - m_csi2_count < (M_uci_sc - M_uci_rvd) * Nl * Qm) {
csi2_d = ((M_uci_sc - M_uci_rvd) * Nl * Qm) / (G_csi2 - m_csi2_count);
csi2_m_re_count = SRSLTE_CEIL(G_csi2 - m_csi2_count, Nl * Qm);
}
M_uci_sc -= csi2_m_re_count;
}
// Leave the rest for UL-SCH
uint32_t ulsch_m_re_count = M_uci_sc;
for (uint32_t i = 0, csi1_i = 0, csi2_i = 0; i < cfg->pusch.M_pusch_sc[l]; i++) {
// Check if RE is reserved for ACK
bool reserved = false;
if (ack_m_re_count != 0 && i % ack_d == 0 && m_ack_count < G_ack_rvd) {
reserved = true;
}
if (ack_m_re_count != 0 && i % ack_d == 0 && m_ack_count < G_ack) {
for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_ack[m_ack_count++] = m_all_count + j;
}
ack_m_re_count--;
} else if (!reserved && csi1_m_re_count != 0 && csi1_i % csi1_d == 0 && m_csi1_count < G_csi1) {
for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_csi1[m_csi1_count++] = m_all_count + j;
}
csi1_m_re_count--;
csi1_i++;
} else if (!reserved && csi2_m_re_count != 0 && csi2_i % csi2_d == 0 && m_csi2_count < G_csi2) {
for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_csi2[m_csi2_count++] = m_all_count + j;
}
csi2_m_re_count--;
csi1_i++;
csi2_i++;
} else {
for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_ulsch[m_ulsch_count++] = m_all_count + j;
}
ulsch_m_re_count--;
if (!reserved) {
csi1_i++;
csi2_i++;
}
}
// Set reserved bits only if there are ACK bits
if (reserved) {
if (cfg->o_ack > 0) {
for (uint32_t j = 0; j < Nl * Qm; j++) {
pos_ack[m_ack_count++] = m_all_count + j;
}
} else {
m_ack_count += Nl * Qm;
}
ack_m_re_count--;
}
// Increment all bit counter
m_all_count += Nl * Qm;
}
// Assert that all RE have been allocated
if (ack_m_re_count != 0) {
ERROR("ack_m_re_count=%d", ack_m_re_count);
}
if (csi1_m_re_count != 0) {
ERROR("csi1_m_re_count=%d", csi1_m_re_count);
}
if (csi2_m_re_count != 0) {
ERROR("csi2_m_re_count=%d", csi2_m_re_count);
}
if (ulsch_m_re_count != 0) {
ERROR("ulsch_m_re_count=%d", ulsch_m_re_count);
}
}
// Update UL-SCH number of encoded bits
q->G_ulsch = m_ulsch_count;
// Assert Number of bits
if (G_ack_rvd != 0 && G_ack_rvd != m_ack_count && cfg->o_ack > 0) {
ERROR("Not matched %d!=%d", G_ack_rvd, m_ack_count);
}
if (G_ack != 0 && G_ack != m_ack_count) {
ERROR("Not matched %d!=%d", G_ack, m_ack_count);
}
q->G_csi1 = m_csi1_count;
if (G_csi1 != 0 && G_csi1 != m_csi1_count) {
ERROR("Not matched %d!=%d", G_csi1, m_csi1_count);
}
if (G_csi2 != 0 && G_csi2 != m_csi2_count) {
ERROR("Not matched %d!=%d", G_csi2, m_csi2_count);
}
// Print debug information if configured for ity
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) {
if (m_ulsch_count != 0) {
DEBUG("UL-SCH bit positions:");
srslte_vec_fprint_i(stdout, (int*)pos_ulsch, m_ulsch_count);
}
if (m_ack_count != 0 && cfg->o_ack > 0) {
DEBUG("HARQ-ACK bit positions [%d]:", m_ack_count);
srslte_vec_fprint_i(stdout, (int*)pos_ack, m_ack_count);
}
if (m_csi1_count != 0) {
DEBUG("CSI part 1 bit positions [%d]:", m_csi1_count);
srslte_vec_fprint_i(stdout, (int*)pos_csi1, m_csi1_count);
}
if (m_csi2_count != 0) {
DEBUG("CSI part 2 bit positions [%d]:", m_csi2_count);
srslte_vec_fprint_i(stdout, (int*)pos_csi2, m_csi2_count);
}
}
return SRSLTE_SUCCESS;
}
static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q,
const srslte_sch_cfg_nr_t* cfg,
const srslte_sch_tb_t* tb,
const uint8_t* data,
const srslte_uci_value_nr_t* uci,
uint16_t rnti)
{ {
// Early return if TB is not enabled // Early return if TB is not enabled
if (!tb->enabled) { if (!tb->enabled) {
@ -447,20 +844,87 @@ static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q,
return SRSLTE_ERROR_OUT_OF_BOUNDS; return SRSLTE_ERROR_OUT_OF_BOUNDS;
} }
// Encode HARQ-ACK bits
int E_uci_ack = srslte_uci_nr_encode_pusch_ack(&q->uci, &q->uci_cfg, uci, q->g_ack);
if (E_uci_ack < SRSLTE_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits");
return SRSLTE_ERROR;
}
q->G_ack = (uint32_t)E_uci_ack;
// Encode CSI part 1
int E_uci_csi1 = srslte_uci_nr_encode_pusch_csi1(&q->uci, &q->uci_cfg, uci, q->g_csi1);
if (E_uci_csi1 < SRSLTE_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits");
return SRSLTE_ERROR;
}
q->G_csi1 = (uint32_t)E_uci_csi1;
// Encode CSI part 2
// ... Not implemented
q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing
if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSLTE_SUCCESS) {
ERROR("Error generating PUSCH mux tables");
return SRSLTE_ERROR;
}
// Encode SCH // Encode SCH
if (srslte_ulsch_nr_encode(&q->sch, &cfg->sch_cfg, tb, data, q->b[tb->cw_idx]) < SRSLTE_SUCCESS) { if (srslte_ulsch_nr_encode(&q->sch, &cfg->sch_cfg, tb, data, q->g_ulsch) < SRSLTE_SUCCESS) {
ERROR("Error in DL-SCH encoding"); ERROR("Error in SCH encoding");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Multiplex UL-SCH with UCI only if it is necessary
uint8_t* b = q->g_ulsch;
if (q->uci_mux) {
// Change b location
b = q->b[tb->cw_idx];
// Multiplex UL-SCH
for (uint32_t i = 0; i < q->G_ulsch; i++) {
b[q->pos_ulsch[i]] = q->g_ulsch[i];
}
// Multiplex CSI part 1
for (uint32_t i = 0; i < q->G_csi1; i++) {
b[q->pos_csi1[i]] = q->g_csi1[i];
}
// Multiplex CSI part 2
for (uint32_t i = 0; i < q->G_csi2; i++) {
b[q->pos_csi2[i]] = q->g_csi2[i];
}
// Multiplex HARQ-ACK
for (uint32_t i = 0; i < q->G_ack; i++) {
b[q->pos_ack[i]] = q->g_ack[i];
}
}
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b="); DEBUG("b=");
srslte_vec_fprint_b(stdout, q->b[tb->cw_idx], tb->nof_bits); srslte_vec_fprint_b(stdout, b, tb->nof_bits);
} }
// 7.3.1.1 Scrambling // 7.3.1.1 Scrambling
uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx); uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx);
srslte_sequence_apply_bit(q->b[tb->cw_idx], q->b[tb->cw_idx], tb->nof_bits, cinit); srslte_sequence_apply_bit(b, q->b[tb->cw_idx], tb->nof_bits, cinit);
// Special Scrambling condition
if (q->uci_cfg.o_ack <= 2) {
for (uint32_t i = 0; i < q->G_ack; i++) {
uint32_t idx = q->pos_ack[i];
if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) {
if (idx != 0) {
q->b[tb->cw_idx][idx] = q->b[tb->cw_idx][idx - 1];
}
} else if (q->g_ack[i] == (uint8_t)UCI_BIT_PLACEHOLDER) {
q->b[tb->cw_idx][idx] = 1;
}
}
}
// 7.3.1.2 Modulation // 7.3.1.2 Modulation
srslte_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits); srslte_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits);
@ -473,11 +937,11 @@ static inline int pusch_nr_encode_codeword(srslte_pusch_nr_t* q,
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_pusch_nr_encode(srslte_pusch_nr_t* q, int srslte_pusch_nr_encode(srslte_pusch_nr_t* q,
const srslte_sch_cfg_nr_t* cfg, const srslte_sch_cfg_nr_t* cfg,
const srslte_sch_grant_nr_t* grant, const srslte_sch_grant_nr_t* grant,
uint8_t* data[SRSLTE_MAX_TB], const srslte_pusch_data_nr_t* data,
cf_t* sf_symbols[SRSLTE_MAX_PORTS]) cf_t* sf_symbols[SRSLTE_MAX_PORTS])
{ {
// Check input pointers // Check input pointers
if (!q || !cfg || !grant || !data || !sf_symbols) { if (!q || !cfg || !grant || !data || !sf_symbols) {
@ -495,12 +959,19 @@ int srslte_pusch_nr_encode(srslte_pusch_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Fill UCI configuration for PUSCH configuration
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSLTE_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH");
return SRSLTE_ERROR;
}
// 7.3.1.1 and 7.3.1.2 // 7.3.1.1 and 7.3.1.2
uint32_t nof_cw = 0; uint32_t nof_cw = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
nof_cw += grant->tb[tb].enabled ? 1 : 0; nof_cw += grant->tb[tb].enabled ? 1 : 0;
if (pusch_nr_encode_codeword(q, cfg, &grant->tb[tb], data[tb], grant->rnti) < SRSLTE_SUCCESS) { if (pusch_nr_encode_codeword(q, cfg, &grant->tb[tb], data[tb].payload, &data[0].uci, grant->rnti) <
SRSLTE_SUCCESS) {
ERROR("Error encoding TB %d", tb); ERROR("Error encoding TB %d", tb);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -568,6 +1039,32 @@ static inline int pusch_nr_decode_codeword(srslte_pusch_nr_t* q,
srslte_vec_fprint_c(stdout, q->d[tb->cw_idx], tb->nof_re); srslte_vec_fprint_c(stdout, q->d[tb->cw_idx], tb->nof_re);
} }
// Calculate HARQ-ACK bits
int n = srslte_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, q->uci_cfg.o_ack);
if (n < SRSLTE_SUCCESS) {
ERROR("Calculating G_ack");
return SRSLTE_ERROR;
}
q->G_ack = (uint32_t)n;
// Calculate CSI part 1 bits
n = srslte_uci_nr_pusch_csi1_nof_bits(&q->uci_cfg);
if (n < SRSLTE_SUCCESS) {
ERROR("Calculating G_csi1");
return SRSLTE_ERROR;
}
q->G_csi1 = (uint32_t)n;
// Calculate CSI part 2 bits
// ... Not implemented
q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing
if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSLTE_SUCCESS) {
ERROR("Error generating PUSCH mux tables");
return SRSLTE_ERROR;
}
// Demodulation // Demodulation
int8_t* llr = (int8_t*)q->b[tb->cw_idx]; int8_t* llr = (int8_t*)q->b[tb->cw_idx];
if (srslte_demod_soft_demodulate_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) { if (srslte_demod_soft_demodulate_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) {
@ -579,23 +1076,76 @@ static inline int pusch_nr_decode_codeword(srslte_pusch_nr_t* q,
res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits); res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
} }
// Change LLR sign
for (uint32_t i = 0; i < tb->nof_bits; i++) {
llr[i] = -llr[i];
}
// Descrambling // Descrambling
srslte_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); srslte_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx));
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b="); DEBUG("b=");
srslte_vec_fprint_b(stdout, q->b[tb->cw_idx], tb->nof_bits); srslte_vec_fprint_bs(stdout, llr, tb->nof_bits);
} }
// Decode SCH // Demultiplex UCI only if necessary
if (srslte_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSLTE_SUCCESS) { if (q->uci_mux) {
ERROR("Error in DL-SCH encoding"); // Demultiplex UL-SCH, change sign
return SRSLTE_ERROR; int8_t* g_ulsch = (int8_t*)q->g_ulsch;
for (uint32_t i = 0; i < q->G_ulsch; i++) {
g_ulsch[i] = -llr[q->pos_ulsch[i]];
}
for (uint32_t i = q->G_ulsch; i < tb->nof_bits; i++) {
g_ulsch[i] = 0;
}
// Demultiplex HARQ-ACK
int8_t* g_ack = (int8_t*)q->g_ack;
for (uint32_t i = 0; i < q->G_ack; i++) {
g_ack[i] = llr[q->pos_ack[i]];
}
// Demultiplex CSI part 1
int8_t* g_csi1 = (int8_t*)q->g_csi1;
for (uint32_t i = 0; i < q->G_csi1; i++) {
g_csi1[i] = llr[q->pos_csi1[i]];
}
// Demultiplex CSI part 2
int8_t* g_csi2 = (int8_t*)q->g_csi2;
for (uint32_t i = 0; i < q->G_csi2; i++) {
g_csi2[i] = llr[q->pos_csi2[i]];
}
// Decode HARQ-ACK
if (q->G_ack) {
if (srslte_uci_nr_decode_pusch_ack(&q->uci, &q->uci_cfg, g_ack, &res->uci)) {
ERROR("Error in UCI decoding");
return SRSLTE_ERROR;
}
}
// Decode CSI part 1
if (q->G_csi1) {
if (srslte_uci_nr_decode_pusch_csi1(&q->uci, &q->uci_cfg, g_csi1, &res->uci)) {
ERROR("Error in UCI decoding");
return SRSLTE_ERROR;
}
}
// Decode CSI part 2
// ... Not implemented
// Change LLR pointer
llr = g_ulsch;
} else {
for (uint32_t i = 0; i < tb->nof_bits; i++) {
llr[i] *= -1;
}
}
// Decode Ul-SCH
if (tb->nof_bits != 0) {
if (srslte_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSLTE_SUCCESS) {
ERROR("Error in SCH decoding");
return SRSLTE_ERROR;
}
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -618,6 +1168,18 @@ int srslte_pusch_nr_decode(srslte_pusch_nr_t* q,
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
} }
// Check number of layers
if (q->max_layers < grant->nof_layers) {
ERROR("Error number of layers (%d) exceeds configured maximum (%d)", grant->nof_layers, q->max_layers);
return SRSLTE_ERROR;
}
// Fill UCI configuration for PUSCH configuration
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSLTE_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH");
return SRSLTE_ERROR;
}
uint32_t nof_cw = 0; uint32_t nof_cw = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
nof_cw += grant->tb[tb].enabled ? 1 : 0; nof_cw += grant->tb[tb].enabled ? 1 : 0;

@ -319,16 +319,13 @@ int srslte_ra_dl_nr_slot_nof_re(const srslte_sch_cfg_nr_t* pdsch_cfg, const srsl
return SRSLTE_MIN(SRSLTE_MAX_NRE_NR, n_re_prime) * n_prb; return SRSLTE_MIN(SRSLTE_MAX_NRE_NR, n_re_prime) * n_prb;
} }
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
#define FLOOR(NUM, DEN) ((NUM) / (DEN))
#define ROUND(NUM, DEN) ((uint32_t)round((NUM) / (DEN)))
#define POW2(N) (1U << (N)) #define POW2(N) (1U << (N))
static uint32_t ra_nr_tbs_from_n_info3(uint32_t n_info) static uint32_t ra_nr_tbs_from_n_info3(uint32_t n_info)
{ {
// quantized intermediate number of information bits // quantized intermediate number of information bits
uint32_t n = (uint32_t)SRSLTE_MAX(3.0, floor(log2(n_info)) - 6.0); uint32_t n = (uint32_t)SRSLTE_MAX(3.0, floor(log2(n_info)) - 6.0);
uint32_t n_info_prime = SRSLTE_MAX(ra_nr_tbs_table[0], POW2(n) * FLOOR(n_info, POW2(n))); uint32_t n_info_prime = SRSLTE_MAX(ra_nr_tbs_table[0], POW2(n) * SRSLTE_FLOOR(n_info, POW2(n)));
// use Table 5.1.3.2-1 find the closest TBS that is not less than n_info_prime // use Table 5.1.3.2-1 find the closest TBS that is not less than n_info_prime
for (uint32_t i = 0; i < RA_NR_TBS_SIZE_TABLE; i++) { for (uint32_t i = 0; i < RA_NR_TBS_SIZE_TABLE; i++) {
@ -344,19 +341,19 @@ static uint32_t ra_nr_tbs_from_n_info4(uint32_t n_info, double R)
{ {
// quantized intermediate number of information bits // quantized intermediate number of information bits
uint32_t n = (uint32_t)(floor(log2(n_info - 24.0)) - 5.0); uint32_t n = (uint32_t)(floor(log2(n_info - 24.0)) - 5.0);
uint32_t n_info_prime = SRSLTE_MAX(3840, POW2(n) * ROUND(n_info - 24.0, POW2(n))); uint32_t n_info_prime = SRSLTE_MAX(3840, POW2(n) * SRSLTE_ROUND(n_info - 24.0, POW2(n)));
if (R <= 0.25) { if (R <= 0.25) {
uint32_t C = CEIL(n_info_prime + 24U, 3816U); uint32_t C = SRSLTE_CEIL(n_info_prime + 24U, 3816U);
return 8U * C * CEIL(n_info_prime + 24U, 8U * C) - 24U; return 8U * C * SRSLTE_CEIL(n_info_prime + 24U, 8U * C) - 24U;
} }
if (n_info_prime > 8424) { if (n_info_prime > 8424) {
uint32_t C = CEIL(n_info_prime + 24U, 8424U); uint32_t C = SRSLTE_CEIL(n_info_prime + 24U, 8424U);
return 8U * C * CEIL(n_info_prime + 24U, 8U * C) - 24U; return 8U * C * SRSLTE_CEIL(n_info_prime + 24U, 8U * C) - 24U;
} }
return 8U * CEIL(n_info_prime + 24U, 8U) - 24U; return 8U * SRSLTE_CEIL(n_info_prime + 24U, 8U) - 24U;
} }
/** /**

@ -51,7 +51,7 @@ static const ue_ra_time_resource_t ue_ul_default_A_lut[16] = {{srslte_sch_mappin
{srslte_sch_mapping_type_A, 3, 0, 14}, {srslte_sch_mapping_type_A, 3, 0, 14},
{srslte_sch_mapping_type_A, 3, 0, 10}}; {srslte_sch_mapping_type_A, 3, 0, 10}};
int srslte_ra_ul_nr_pdsch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant) int srslte_ra_ul_nr_pusch_time_resource_default_A(uint32_t scs_cfg, uint32_t m, srslte_sch_grant_nr_t* grant)
{ {
uint32_t j[4] = {1, 1, 2, 3}; uint32_t j[4] = {1, 1, 2, 3};
@ -150,7 +150,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg,
if (ss_type == srslte_search_space_type_rar) { if (ss_type == srslte_search_space_type_rar) {
// Row 1 // Row 1
if (cfg->nof_common_time_ra == 0) { if (cfg->nof_common_time_ra == 0) {
srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant);
} else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION && m < cfg->nof_common_time_ra) { } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION && m < cfg->nof_common_time_ra) {
ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant);
} else { } else {
@ -163,7 +163,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg,
SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id == 0) { SRSLTE_SEARCH_SPACE_IS_COMMON(ss_type) && coreset_id == 0) {
// Row 2 // Row 2
if (cfg->nof_common_time_ra == 0) { if (cfg->nof_common_time_ra == 0) {
srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant);
} else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION) { } else if (m < SRSLTE_MAX_NOF_DL_ALLOCATION) {
ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant);
} }
@ -177,7 +177,7 @@ int srslte_ra_ul_nr_time(const srslte_sch_hl_cfg_nr_t* cfg,
} else if (cfg->nof_common_time_ra > 0) { } else if (cfg->nof_common_time_ra > 0) {
ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant); ra_ul_nr_time_hl(&cfg->common_time_ra[m], grant);
} else { } else {
srslte_ra_ul_nr_pdsch_time_resource_default_A(cfg->scs_cfg, m, grant); srslte_ra_ul_nr_pusch_time_resource_default_A(cfg->scs_cfg, m, grant);
} }
} else { } else {
ERROR("Unhandled case"); ERROR("Unhandled case");
@ -382,7 +382,7 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r
} }
// Compute total number of UCI bits // Compute total number of UCI bits
uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
// Add CRC bits if any // Add CRC bits if any
O_total += srslte_uci_nr_crc_len(O_total); O_total += srslte_uci_nr_crc_len(O_total);
@ -470,9 +470,9 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
// - At least one positive SR // - At least one positive SR
// - up to 2 HARQ-ACK // - up to 2 HARQ-ACK
// - No CSI report // - No CSI report
if (uci_cfg->sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && if (uci_cfg->pucch.sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
uci_cfg->nof_csi == 0) { uci_cfg->nof_csi == 0) {
uint32_t sr_resource_id = uci_cfg->sr_resource_id; uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) { if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) {
ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES); ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES);
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -495,7 +495,7 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
// - More than 2 HARQ-ACK // - More than 2 HARQ-ACK
// - No CSI report // - No CSI report
if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) {
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource);
} }
// Use format 2, 3 or 4 CSI report resource from higher layers // Use format 2, 3 or 4 CSI report resource from higher layers
@ -511,10 +511,10 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg,
// a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size // a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size
// transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs. // transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs.
if (!pucch_cfg->enabled) { if (!pucch_cfg->enabled) {
uint32_t r_pucch = (2 * uci_cfg->n_cce_0) + 2 * uci_cfg->pucch_resource_id; uint32_t r_pucch = (2 * uci_cfg->pucch.n_cce_0) + 2 * uci_cfg->pucch.resource_id;
return ra_ul_nr_pucch_resource_default(r_pucch, resource); return ra_ul_nr_pucch_resource_default(r_pucch, resource);
} }
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource);
} }
uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K) uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K)

@ -74,10 +74,10 @@ uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb)
return 273; return 273;
} }
int srslte_sch_nr_fill_cfg(srslte_sch_nr_t* q, int srslte_sch_nr_fill_tb_info(const srslte_carrier_nr_t* carrier,
const srslte_sch_cfg_t* sch_cfg, const srslte_sch_cfg_t* sch_cfg,
const srslte_sch_tb_t* tb, const srslte_sch_tb_t* tb,
srslte_sch_nr_common_cfg_t* cfg) srslte_sch_nr_tb_info_t* cfg)
{ {
if (!sch_cfg || !tb || !cfg) { if (!sch_cfg || !tb || !cfg) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
@ -120,10 +120,10 @@ int srslte_sch_nr_fill_cfg(srslte_sch_nr_t* q,
cfg->Nl = tb->N_L; cfg->Nl = tb->N_L;
// Calculate Nref // Calculate Nref
uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(q->carrier.nof_prb); uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(carrier->nof_prb);
double TCR_lbrm = 948.0 / 1024.0; double TCR_lbrm = 948.0 / 1024.0;
uint32_t Qm_lbrm = (sch_cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6; uint32_t Qm_lbrm = (sch_cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6;
uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, TCR_lbrm, Qm_lbrm, q->carrier.max_mimo_layers); uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, TCR_lbrm, Qm_lbrm, carrier->max_mimo_layers);
double R = 2.0 / 3.0; double R = 2.0 / 3.0;
cfg->Nref = ceil(TBS_LRBM / (cbsegm.C * R)); cfg->Nref = ceil(TBS_LRBM / (cbsegm.C * R));
@ -137,22 +137,12 @@ int srslte_sch_nr_fill_cfg(srslte_sch_nr_t* q,
cfg->C = cbsegm.C; cfg->C = cbsegm.C;
cfg->Cp = cbsegm.C; cfg->Cp = cbsegm.C;
// Select encoder
cfg->encoder = (bg == BG1) ? q->encoder_bg1[cfg->Z] : q->encoder_bg2[cfg->Z];
// Select decoder
cfg->decoder = (bg == BG1) ? q->decoder_bg1[cfg->Z] : q->decoder_bg2[cfg->Z];
// Select CRC for TB
cfg->crc_tb = (cbsegm.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
#define MOD(NUM, DEN) ((NUM) % (DEN)) #define MOD(NUM, DEN) ((NUM) % (DEN))
static inline uint32_t sch_nr_get_E(const srslte_sch_nr_common_cfg_t* cfg, uint32_t j) static inline uint32_t sch_nr_get_E(const srslte_sch_nr_tb_info_t* cfg, uint32_t j)
{ {
if (cfg->Nl == 0 || cfg->Qm == 0 || cfg->Cp == 0) { if (cfg->Nl == 0 || cfg->Qm == 0 || cfg->Cp == 0) {
ERROR("Invalid Nl (%d), Qm (%d) or Cp (%d)", cfg->Nl, cfg->Qm, cfg->Cp); ERROR("Invalid Nl (%d), Qm (%d) or Cp (%d)", cfg->Nl, cfg->Qm, cfg->Cp);
@ -162,7 +152,7 @@ static inline uint32_t sch_nr_get_E(const srslte_sch_nr_common_cfg_t* cfg, uint3
if (j <= (cfg->Cp - MOD(cfg->G / (cfg->Nl * cfg->Qm), cfg->Cp) - 1)) { if (j <= (cfg->Cp - MOD(cfg->G / (cfg->Nl * cfg->Qm), cfg->Cp) - 1)) {
return cfg->Nl * cfg->Qm * (cfg->G / (cfg->Nl * cfg->Qm * cfg->Cp)); return cfg->Nl * cfg->Qm * (cfg->G / (cfg->Nl * cfg->Qm * cfg->Cp));
} }
return cfg->Nl * cfg->Qm * CEIL(cfg->G, cfg->Nl * cfg->Qm * cfg->Cp); return cfg->Nl * cfg->Qm * SRSLTE_CEIL(cfg->G, cfg->Nl * cfg->Qm * cfg->Cp);
} }
static inline int sch_nr_init_common(srslte_sch_nr_t* q) static inline int sch_nr_init_common(srslte_sch_nr_t* q)
@ -225,21 +215,23 @@ int srslte_sch_nr_init_tx(srslte_sch_nr_t* q, const srslte_sch_nr_args_t* args)
continue; continue;
} }
q->encoder_bg1[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); q->encoder_bg1[ls] = SRSLTE_MEM_ALLOC(srslte_ldpc_encoder_t, 1);
if (!q->encoder_bg1[ls]) { if (!q->encoder_bg1[ls]) {
ERROR("Error: calloc"); ERROR("Error: calloc");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
SRSLTE_MEM_ZERO(q->encoder_bg1[ls], srslte_ldpc_encoder_t, 1);
if (srslte_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSLTE_SUCCESS) { if (srslte_ldpc_encoder_init(q->encoder_bg1[ls], encoder_type, BG1, ls) < SRSLTE_SUCCESS) {
ERROR("Error: initialising BG1 LDPC encoder for ls=%d", ls); ERROR("Error: initialising BG1 LDPC encoder for ls=%d", ls);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
q->encoder_bg2[ls] = calloc(1, sizeof(srslte_ldpc_encoder_t)); q->encoder_bg2[ls] = SRSLTE_MEM_ALLOC(srslte_ldpc_encoder_t, 1);
if (!q->encoder_bg2[ls]) { if (!q->encoder_bg2[ls]) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
SRSLTE_MEM_ZERO(q->encoder_bg2[ls], srslte_ldpc_encoder_t, 1);
if (srslte_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSLTE_SUCCESS) { if (srslte_ldpc_encoder_init(q->encoder_bg2[ls], encoder_type, BG2, ls) < SRSLTE_SUCCESS) {
ERROR("Error: initialising BG2 LDPC encoder for ls=%d", ls); ERROR("Error: initialising BG2 LDPC encoder for ls=%d", ls);
@ -387,19 +379,23 @@ static inline int sch_nr_encode(srslte_sch_nr_t* q,
const uint8_t* input_ptr = data; const uint8_t* input_ptr = data;
uint8_t* output_ptr = e_bits; uint8_t* output_ptr = e_bits;
srslte_sch_nr_common_cfg_t cfg = {}; srslte_sch_nr_tb_info_t cfg = {};
if (srslte_sch_nr_fill_cfg(q, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { if (srslte_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Select encoder and CRC
srslte_ldpc_encoder_t* encoder = (cfg.bg == BG1) ? q->encoder_bg1[cfg.Z] : q->encoder_bg2[cfg.Z];
srslte_crc_t* crc_tb = (cfg.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16;
// Check encoder // Check encoder
if (cfg.encoder == NULL) { if (encoder == NULL) {
ERROR("Error: encoder for lifting size Z=%d not found (tbs=%d)", cfg.Z, tb->tbs); ERROR("Error: encoder for lifting size Z=%d not found (tbs=%d)", cfg.Z, tb->tbs);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Check CRC for TB // Check CRC for TB
if (cfg.crc_tb == NULL) { if (crc_tb == NULL) {
ERROR("Error: CRC for TB not found"); ERROR("Error: CRC for TB not found");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -413,16 +409,16 @@ static inline int sch_nr_encode(srslte_sch_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (tb->softbuffer.tx->max_cb_size < (cfg.encoder->liftN - 2 * cfg.Z)) { if (tb->softbuffer.tx->max_cb_size < (encoder->liftN - 2 * cfg.Z)) {
ERROR("Soft-buffer code-block maximum size insufficient (max_cb_size=%d) for a TBS=%d, requires %d.", ERROR("Soft-buffer code-block maximum size insufficient (max_cb_size=%d) for a TBS=%d, requires %d.",
tb->softbuffer.tx->max_cb_size, tb->softbuffer.tx->max_cb_size,
tb->tbs, tb->tbs,
(cfg.encoder->liftN - 2 * cfg.Z)); (encoder->liftN - 2 * cfg.Z));
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Calculate TB CRC // Calculate TB CRC
uint32_t checksum_tb = srslte_crc_checksum_byte(cfg.crc_tb, data, tb->tbs); uint32_t checksum_tb = srslte_crc_checksum_byte(crc_tb, data, tb->tbs);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) {
DEBUG("tb="); DEBUG("tb=");
srslte_vec_fprint_byte(stdout, data, tb->tbs / 8); srslte_vec_fprint_byte(stdout, data, tb->tbs / 8);
@ -477,11 +473,11 @@ static inline int sch_nr_encode(srslte_sch_nr_t* q,
} }
// Encode code block // Encode code block
srslte_ldpc_encoder_encode(cfg.encoder, q->temp_cb, rm_buffer, cfg.Kr); srslte_ldpc_encoder_encode(encoder, q->temp_cb, rm_buffer, cfg.Kr);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) {
DEBUG("encoded="); DEBUG("encoded=");
srslte_vec_fprint_b(stdout, rm_buffer, cfg.encoder->liftN - 2 * cfg.encoder->ls); srslte_vec_fprint_b(stdout, rm_buffer, encoder->liftN - 2 * encoder->ls);
} }
} }
@ -525,25 +521,29 @@ int sch_nr_decode(srslte_sch_nr_t* q,
int8_t* input_ptr = e_bits; int8_t* input_ptr = e_bits;
srslte_sch_nr_common_cfg_t cfg = {}; srslte_sch_nr_tb_info_t cfg = {};
if (srslte_sch_nr_fill_cfg(q, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) { if (srslte_sch_nr_fill_tb_info(&q->carrier, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Select encoder and CRC
srslte_ldpc_decoder_t* decoder = (cfg.bg == BG1) ? q->decoder_bg1[cfg.Z] : q->decoder_bg2[cfg.Z];
srslte_crc_t* crc_tb = (cfg.L_tb == 24) ? &q->crc_tb_24 : &q->crc_tb_16;
// Check decoder // Check decoder
if (cfg.decoder == NULL) { if (decoder == NULL) {
ERROR("Error: decoder for lifting size Z=%d not found", cfg.Z); ERROR("Error: decoder for lifting size Z=%d not found", cfg.Z);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Check CRC for TB // Check CRC for TB
if (cfg.crc_tb == NULL) { if (crc_tb == NULL) {
ERROR("Error: CRC for TB not found"); ERROR("Error: CRC for TB not found");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Soft-buffer number of code-block protection // Soft-buffer number of code-block protection
if (tb->softbuffer.rx->max_cb < cfg.Cp || tb->softbuffer.rx->max_cb_size < (cfg.decoder->liftN - 2 * cfg.Z)) { if (tb->softbuffer.rx->max_cb < cfg.Cp || tb->softbuffer.rx->max_cb_size < (decoder->liftN - 2 * cfg.Z)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -593,7 +593,7 @@ int sch_nr_decode(srslte_sch_nr_t* q,
srslte_ldpc_rm_rx_c(&q->rx_rm, input_ptr, rm_buffer, E, cfg.F, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref); srslte_ldpc_rm_rx_c(&q->rx_rm, input_ptr, rm_buffer, E, cfg.F, cfg.bg, cfg.Z, tb->rv, tb->mod, cfg.Nref);
// Decode // Decode
srslte_ldpc_decoder_decode_c(cfg.decoder, rm_buffer, q->temp_cb); srslte_ldpc_decoder_decode_c(decoder, rm_buffer, q->temp_cb);
// Compute CB CRC // Compute CB CRC
uint32_t cb_len = cfg.Kp - cfg.L_cb; uint32_t cb_len = cfg.Kp - cfg.L_cb;
@ -657,7 +657,7 @@ int sch_nr_decode(srslte_sch_nr_t* q,
} }
// Calculate TB CRC from packed data // Calculate TB CRC from packed data
uint32_t checksum1 = srslte_crc_checksum_byte(cfg.crc_tb, data, tb->tbs); uint32_t checksum1 = srslte_crc_checksum_byte(crc_tb, data, tb->tbs);
*crc_ok = (checksum1 == checksum2 && !all_zeros); *crc_ok = (checksum1 == checksum2 && !all_zeros);
SCH_INFO_RX("TB: TBS=%d; CRC={%06x, %06x}", tb->tbs, checksum1, checksum2); SCH_INFO_RX("TB: TBS=%d; CRC={%06x, %06x}", tb->tbs, checksum1, checksum2);

@ -643,6 +643,17 @@ add_nr_test(pdsch_nr_test pdsch_nr_test -p 6 -m 20)
add_executable(pusch_nr_test pusch_nr_test.c) add_executable(pusch_nr_test pusch_nr_test.c)
target_link_libraries(pusch_nr_test srslte_phy) target_link_libraries(pusch_nr_test srslte_phy)
add_nr_test(pusch_nr_test pusch_nr_test -p 6 -m 20) add_nr_test(pusch_nr_test pusch_nr_test -p 6 -m 20)
add_nr_test(pusch_nr_ack1_test pusch_nr_test -p 50 -m 20 -A 1)
add_nr_test(pusch_nr_ack2_test pusch_nr_test -p 50 -m 20 -A 2)
add_nr_test(pusch_nr_ack4_test pusch_nr_test -p 50 -m 20 -A 4)
add_nr_test(pusch_nr_ack20_test pusch_nr_test -p 50 -m 20 -A 20)
add_nr_test(pusch_nr_csi4_test pusch_nr_test -p 50 -m 20 -C 4)
add_nr_test(pusch_nr_csi20_test pusch_nr_test -p 50 -m 20 -C 20)
add_nr_test(pusch_nr_ack1_csi4_test pusch_nr_test -p 50 -m 20 -A 1 -C 4)
add_nr_test(pusch_nr_ack2_csi4_test pusch_nr_test -p 50 -m 20 -A 2 -C 4)
add_nr_test(pusch_nr_ack4_csi4_test pusch_nr_test -p 50 -m 20 -A 4 -C 4)
add_nr_test(pusch_nr_ack20_csi4_test pusch_nr_test -p 50 -m 20 -A 20 -C 4)
add_executable(pdcch_nr_test pdcch_nr_test.c) add_executable(pdcch_nr_test pdcch_nr_test.c)
target_link_libraries(pdcch_nr_test srslte_phy) target_link_libraries(pdcch_nr_test srslte_phy)

@ -62,15 +62,14 @@ static int test_pucch_format0(srslte_pucch_nr_t* pucch, const srslte_pucch_nr_co
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11; for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11;
resource.initial_cyclic_shift++) { resource.initial_cyclic_shift++) {
for (uint32_t m_cs = 0; m_cs <= 6; m_cs += 2) { for (uint32_t m_cs = 0; m_cs <= 6; m_cs += 2) {
TESTASSERT(srslte_pucch_nr_format0_encode(pucch, &carrier, cfg, &slot, &resource, m_cs, slot_symbols) == TESTASSERT(srslte_pucch_nr_format0_encode(pucch, cfg, &slot, &resource, m_cs, slot_symbols) ==
SRSLTE_SUCCESS); SRSLTE_SUCCESS);
// Measure PUCCH format 0 for all possible values of m_cs // Measure PUCCH format 0 for all possible values of m_cs
for (uint32_t m_cs_test = 0; m_cs_test <= 6; m_cs_test += 2) { for (uint32_t m_cs_test = 0; m_cs_test <= 6; m_cs_test += 2) {
srslte_pucch_nr_measure_t measure = {}; srslte_pucch_nr_measure_t measure = {};
TESTASSERT(srslte_pucch_nr_format0_measure( TESTASSERT(srslte_pucch_nr_format0_measure(
pucch, &carrier, cfg, &slot, &resource, m_cs_test, slot_symbols, &measure) == pucch, cfg, &slot, &resource, m_cs_test, slot_symbols, &measure) == SRSLTE_SUCCESS);
SRSLTE_SUCCESS);
if (m_cs == m_cs_test) { if (m_cs == m_cs_test) {
TESTASSERT(fabsf(measure.epre - 1) < 0.001); TESTASSERT(fabsf(measure.epre - 1) < 0.001);
@ -124,8 +123,8 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch,
} }
// Encode PUCCH // Encode PUCCH
TESTASSERT(srslte_pucch_nr_format1_encode( TESTASSERT(srslte_pucch_nr_format1_encode(pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) ==
pucch, &carrier, cfg, &slot, &resource, b, nof_bits, slot_symbols) == SRSLTE_SUCCESS); SRSLTE_SUCCESS);
// Put DMRS // Put DMRS
TESTASSERT(srslte_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) == TESTASSERT(srslte_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
@ -146,7 +145,7 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch,
// Decode PUCCH // Decode PUCCH
uint8_t b_rx[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; uint8_t b_rx[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
TESTASSERT(srslte_pucch_nr_format1_decode( TESTASSERT(srslte_pucch_nr_format1_decode(
pucch, &carrier, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits) == pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits) ==
SRSLTE_SUCCESS); SRSLTE_SUCCESS);
// Check received bits // Check received bits
@ -211,8 +210,7 @@ static int test_pucch_format2(srslte_pucch_nr_t* pucch,
// Encode PUCCH // Encode PUCCH
TESTASSERT(srslte_pucch_nr_format_2_3_4_encode( TESTASSERT(srslte_pucch_nr_format_2_3_4_encode(
pucch, &carrier, cfg, &slot, &resource, &uci_cfg, &uci_value, slot_symbols) == pucch, cfg, &slot, &resource, &uci_cfg, &uci_value, slot_symbols) == SRSLTE_SUCCESS);
SRSLTE_SUCCESS);
// Put DMRS // Put DMRS
TESTASSERT(srslte_dmrs_pucch_format2_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) == TESTASSERT(srslte_dmrs_pucch_format2_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
@ -235,10 +233,9 @@ static int test_pucch_format2(srslte_pucch_nr_t* pucch,
// Decode PUCCH // Decode PUCCH
srslte_uci_value_nr_t uci_value_rx = {}; srslte_uci_value_nr_t uci_value_rx = {};
TESTASSERT( TESTASSERT(srslte_pucch_nr_format_2_3_4_decode(
srslte_pucch_nr_format_2_3_4_decode( pucch, cfg, &slot, &resource, &uci_cfg, chest_res, slot_symbols, &uci_value_rx) ==
pucch, &carrier, cfg, &slot, &resource, &uci_cfg, chest_res, slot_symbols, &uci_value_rx) == SRSLTE_SUCCESS);
SRSLTE_SUCCESS);
TESTASSERT(uci_value_rx.valid == true); TESTASSERT(uci_value_rx.valid == true);
@ -320,6 +317,11 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
if (srslte_pucch_nr_set_carrier(&pucch, &carrier) < SRSLTE_SUCCESS) {
ERROR("PUCCH set carrier");
goto clean_exit;
}
if (srslte_chest_ul_res_init(&chest_res, carrier.nof_prb)) { if (srslte_chest_ul_res_init(&chest_res, carrier.nof_prb)) {
ERROR("Chest UL"); ERROR("Chest UL");
goto clean_exit; goto clean_exit;

@ -36,11 +36,12 @@ static srslte_carrier_nr_t carrier = {
1 // max_mimo_layers 1 // max_mimo_layers
}; };
static uint32_t n_prb = 0; // Set to 0 for steering static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering static uint32_t mcs = 30; // Set to 30 for steering
static srslte_sch_cfg_nr_t pusch_cfg = {}; static srslte_sch_cfg_nr_t pusch_cfg = {};
static srslte_sch_grant_nr_t pusch_grant = {}; static uint16_t rnti = 0x1234;
static uint16_t rnti = 0x1234; static uint32_t nof_ack_bits = 0;
static uint32_t nof_csi_bits = 0;
void usage(char* prog) void usage(char* prog)
{ {
@ -50,13 +51,15 @@ void usage(char* prog)
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
srslte_mcs_table_to_str(pusch_cfg.sch_cfg.mcs_table)); srslte_mcs_table_to_str(pusch_cfg.sch_cfg.mcs_table));
printf("\t-L Provide number of layers [Default %d]\n", carrier.max_mimo_layers); printf("\t-L Provide number of layers [Default %d]\n", carrier.max_mimo_layers);
printf("\t-A Provide a number of HARQ-ACK bits [Default %d]\n", nof_ack_bits);
printf("\t-C Provide a number of CSI bits [Default %d]\n", nof_csi_bits);
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }
int parse_args(int argc, char** argv) int parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "pmTLv")) != -1) { while ((opt = getopt(argc, argv, "pmTLACv")) != -1) {
switch (opt) { switch (opt) {
case 'p': case 'p':
n_prb = (uint32_t)strtol(argv[optind], NULL, 10); n_prb = (uint32_t)strtol(argv[optind], NULL, 10);
@ -70,6 +73,12 @@ int parse_args(int argc, char** argv)
case 'L': case 'L':
carrier.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10); carrier.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'A':
nof_ack_bits = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'C':
nof_csi_bits = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -84,16 +93,15 @@ int parse_args(int argc, char** argv)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
srslte_pusch_nr_t pusch_tx = {}; srslte_pusch_nr_t pusch_tx = {};
srslte_pusch_nr_t pusch_rx = {}; srslte_pusch_nr_t pusch_rx = {};
srslte_chest_dl_res_t chest = {}; srslte_chest_dl_res_t chest = {};
srslte_pusch_res_nr_t pusch_res[SRSLTE_MAX_TB] = {}; srslte_random_t rand_gen = srslte_random_init(1234);
srslte_random_t rand_gen = srslte_random_init(1234);
uint8_t* data_tx[SRSLTE_MAX_TB] = {}; srslte_pusch_data_nr_t data_tx[SRSLTE_MAX_TB] = {};
uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {}; srslte_pusch_res_nr_t data_rx[SRSLTE_MAX_CODEWORDS] = {};
cf_t* sf_symbols[SRSLTE_MAX_LAYERS_NR] = {}; cf_t* sf_symbols[SRSLTE_MAX_LAYERS_NR] = {};
// Set default PUSCH configuration // Set default PUSCH configuration
pusch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam; pusch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam;
@ -135,14 +143,12 @@ int main(int argc, char** argv)
} }
for (uint32_t i = 0; i < pusch_tx.max_cw; i++) { for (uint32_t i = 0; i < pusch_tx.max_cw; i++) {
data_tx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR); data_tx[i].payload = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
data_rx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR); data_rx[i].payload = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
if (data_tx[i] == NULL || data_rx[i] == NULL) { if (data_tx[i].payload == NULL || data_rx[i].payload == NULL) {
ERROR("Error malloc"); ERROR("Error malloc");
goto clean_exit; goto clean_exit;
} }
pusch_res[i].payload = data_rx[i];
} }
srslte_softbuffer_tx_t softbuffer_tx = {}; srslte_softbuffer_tx_t softbuffer_tx = {};
@ -161,20 +167,20 @@ int main(int argc, char** argv)
} }
// Use grant default A time resources with m=0 // Use grant default A time resources with m=0
if (srslte_ra_ul_nr_pdsch_time_resource_default_A(carrier.numerology, 0, &pusch_grant) < SRSLTE_SUCCESS) { if (srslte_ra_ul_nr_pusch_time_resource_default_A(carrier.numerology, 0, &pusch_cfg.grant) < SRSLTE_SUCCESS) {
ERROR("Error loading default grant"); ERROR("Error loading default grant");
goto clean_exit; goto clean_exit;
} }
// Load number of DMRS CDM groups without data // Load number of DMRS CDM groups without data
if (srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_grant) < SRSLTE_SUCCESS) { if (srslte_ra_ul_nr_nof_dmrs_cdm_groups_without_data_format_0_0(&pusch_cfg, &pusch_cfg.grant) < SRSLTE_SUCCESS) {
ERROR("Error loading number of DMRS CDM groups without data"); ERROR("Error loading number of DMRS CDM groups without data");
goto clean_exit; goto clean_exit;
} }
pusch_grant.nof_layers = carrier.max_mimo_layers; pusch_cfg.grant.nof_layers = carrier.max_mimo_layers;
pusch_grant.dci_format = srslte_dci_format_nr_1_0; pusch_cfg.grant.dci_format = srslte_dci_format_nr_1_0;
pusch_grant.rnti = rnti; pusch_cfg.grant.rnti = rnti;
uint32_t n_prb_start = 1; uint32_t n_prb_start = 1;
uint32_t n_prb_end = carrier.nof_prb + 1; uint32_t n_prb_end = carrier.nof_prb + 1;
@ -190,6 +196,10 @@ int main(int argc, char** argv)
mcs_end = SRSLTE_MIN(mcs + 1, mcs_end); mcs_end = SRSLTE_MIN(mcs + 1, mcs_end);
} }
pusch_cfg.scaling = 0.5f;
pusch_cfg.beta_harq_ack_offset = 2.0f;
pusch_cfg.beta_csi_part1_offset = 2.0f;
if (srslte_chest_dl_res_init(&chest, carrier.nof_prb) < SRSLTE_SUCCESS) { if (srslte_chest_dl_res_init(&chest, carrier.nof_prb) < SRSLTE_SUCCESS) {
ERROR("Initiating chest"); ERROR("Initiating chest");
goto clean_exit; goto clean_exit;
@ -198,65 +208,91 @@ int main(int argc, char** argv)
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
for (mcs = mcs_start; mcs < mcs_end; mcs++) { for (mcs = mcs_start; mcs < mcs_end; mcs++) {
for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) {
pusch_grant.prb_idx[n] = (n < n_prb); pusch_cfg.grant.prb_idx[n] = (n < n_prb);
} }
pusch_cfg.grant.nof_prb = n_prb;
pusch_grant.dci_format = srslte_dci_format_nr_0_0; pusch_cfg.grant.dci_format = srslte_dci_format_nr_0_0;
if (srslte_ra_nr_fill_tb(&pusch_cfg, &pusch_grant, mcs, &pusch_grant.tb[0]) < SRSLTE_SUCCESS) { if (srslte_ra_nr_fill_tb(&pusch_cfg, &pusch_cfg.grant, mcs, &pusch_cfg.grant.tb[0]) < SRSLTE_SUCCESS) {
ERROR("Error filing tb"); ERROR("Error filing tb");
goto clean_exit; goto clean_exit;
} }
// Generate SCH payload
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
// Skip TB if no allocated // Skip TB if no allocated
if (data_tx[tb] == NULL) { if (data_tx[tb].payload == NULL) {
continue; continue;
} }
for (uint32_t i = 0; i < pusch_grant.tb[tb].tbs; i++) { for (uint32_t i = 0; i < pusch_cfg.grant.tb[tb].tbs; i++) {
data_tx[tb][i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); data_tx[tb].payload[i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
}
pusch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx;
}
// Generate HARQ ACK bits
if (nof_ack_bits > 0) {
pusch_cfg.uci.o_ack = nof_ack_bits;
for (uint32_t i = 0; i < nof_ack_bits; i++) {
data_tx->uci.ack[i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, 1);
}
}
// Generate CSI report bits
uint8_t csi_report_tx[SRSLTE_UCI_NR_MAX_CSI1_BITS] = {};
uint8_t csi_report_rx[SRSLTE_UCI_NR_MAX_CSI1_BITS] = {};
if (nof_csi_bits > 0) {
pusch_cfg.uci.csi[0].quantity = SRSLTE_CSI_REPORT_QUANTITY_NONE;
pusch_cfg.uci.csi[0].K_csi_rs = nof_csi_bits;
pusch_cfg.uci.nof_csi = 1;
data_tx->uci.csi[0].none = csi_report_tx;
for (uint32_t i = 0; i < nof_csi_bits; i++) {
csi_report_tx[i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, 1);
} }
pusch_grant.tb[tb].softbuffer.tx = &softbuffer_tx;
data_rx->uci.csi[0].none = csi_report_rx;
} }
if (srslte_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_grant, data_tx, sf_symbols) < SRSLTE_SUCCESS) { if (srslte_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, data_tx, sf_symbols) < SRSLTE_SUCCESS) {
ERROR("Error encoding"); ERROR("Error encoding");
goto clean_exit; goto clean_exit;
} }
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
pusch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; pusch_cfg.grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srslte_softbuffer_rx_reset(pusch_grant.tb[tb].softbuffer.rx); srslte_softbuffer_rx_reset(pusch_cfg.grant.tb[tb].softbuffer.rx);
} }
for (uint32_t i = 0; i < pusch_grant.tb->nof_re; i++) { for (uint32_t i = 0; i < pusch_cfg.grant.tb->nof_re; i++) {
chest.ce[0][0][i] = 1.0f; chest.ce[0][0][i] = 1.0f;
} }
chest.nof_re = pusch_grant.tb->nof_re; chest.nof_re = pusch_cfg.grant.tb->nof_re;
if (srslte_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_grant, &chest, sf_symbols, pusch_res) < SRSLTE_SUCCESS) { if (srslte_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, data_rx) <
SRSLTE_SUCCESS) {
ERROR("Error encoding"); ERROR("Error encoding");
goto clean_exit; goto clean_exit;
} }
if (pusch_res->evm > 0.001f) { if (data_rx[0].evm > 0.001f) {
ERROR("Error PUSCH EVM is too high %f", pusch_res->evm); ERROR("Error PUSCH EVM is too high %f", data_rx[0].evm);
goto clean_exit; goto clean_exit;
} }
float mse = 0.0f; float mse = 0.0f;
uint32_t nof_re = srslte_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_grant); uint32_t nof_re = srslte_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_cfg.grant);
for (uint32_t i = 0; i < pusch_grant.nof_layers; i++) { for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
for (uint32_t j = 0; j < nof_re; j++) { for (uint32_t j = 0; j < nof_re; j++) {
mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]); mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]);
} }
} }
if (nof_re * pusch_grant.nof_layers > 0) { if (nof_re * pusch_cfg.grant.nof_layers > 0) {
mse = mse / (nof_re * pusch_grant.nof_layers); mse = mse / (nof_re * pusch_cfg.grant.nof_layers);
} }
if (mse > 0.001) { if (mse > 0.001) {
ERROR("MSE error (%f) is too high", mse); ERROR("MSE error (%f) is too high", mse);
for (uint32_t i = 0; i < pusch_grant.nof_layers; i++) { for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) {
printf("d_tx[%d]=", i); printf("d_tx[%d]=", i);
srslte_vec_fprint_c(stdout, pusch_tx.d[i], nof_re); srslte_vec_fprint_c(stdout, pusch_tx.d[i], nof_re);
printf("d_rx[%d]=", i); printf("d_rx[%d]=", i);
@ -265,21 +301,55 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
if (!pusch_res[0].crc) { // Validate UL-SCH CRC check
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_grant.tb[0].tbs); if (!data_rx[0].crc) {
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs);
goto clean_exit; goto clean_exit;
} }
if (memcmp(data_tx[0], data_rx[0], pusch_grant.tb[0].tbs / 8) != 0) { // Validate UL-SCH payload
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_grant.tb[0].tbs); if (memcmp(data_tx[0].payload, data_rx[0].payload, pusch_cfg.grant.tb[0].tbs / 8) != 0) {
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;", n_prb, mcs, pusch_cfg.grant.tb[0].tbs);
printf("Tx data: "); printf("Tx data: ");
srslte_vec_fprint_byte(stdout, data_tx[0], pusch_grant.tb[0].tbs / 8); srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8);
printf("Rx data: "); printf("Rx data: ");
srslte_vec_fprint_byte(stdout, data_rx[0], pusch_grant.tb[0].tbs / 8); srslte_vec_fprint_byte(stdout, data_tx[0].payload, pusch_cfg.grant.tb[0].tbs / 8);
goto clean_exit; goto clean_exit;
} }
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_grant.tb[0].tbs, pusch_res[0].evm); // Validate UCI is decoded successfully
if (nof_ack_bits > 0 || nof_csi_bits > 0) {
if (!data_rx[0].uci.valid) {
ERROR("UCI data was not decoded ok");
goto clean_exit;
}
}
// Validate HARQ-ACK is decoded successfully
if (nof_ack_bits > 0) {
if (memcmp(data_tx[0].uci.ack, data_rx[0].uci.ack, nof_ack_bits) != 0) {
ERROR("UCI HARQ-ACK bits are unmatched");
printf("Tx data: ");
srslte_vec_fprint_byte(stdout, data_tx[0].uci.ack, nof_ack_bits);
printf("Rx data: ");
srslte_vec_fprint_byte(stdout, data_rx[0].uci.ack, nof_ack_bits);
goto clean_exit;
}
}
// Validate CSI is decoded successfully
if (nof_csi_bits > 0) {
if (memcmp(data_tx[0].uci.csi[0].none, data_rx[0].uci.csi[0].none, nof_csi_bits) != 0) {
ERROR("UCI CSI bits are unmatched");
printf("Tx data: ");
srslte_vec_fprint_byte(stdout, data_tx[0].uci.csi[0].none, nof_csi_bits);
printf("Rx data: ");
srslte_vec_fprint_byte(stdout, data_rx[0].uci.csi[0].none, nof_csi_bits);
goto clean_exit;
}
}
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx[0].evm);
} }
} }
@ -291,11 +361,11 @@ clean_exit:
srslte_pusch_nr_free(&pusch_tx); srslte_pusch_nr_free(&pusch_tx);
srslte_pusch_nr_free(&pusch_rx); srslte_pusch_nr_free(&pusch_rx);
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data_tx[i]) { if (data_tx[i].payload) {
free(data_tx[i]); free(data_tx[i].payload);
} }
if (data_rx[i]) { if (data_rx[i].payload) {
free(data_rx[i]); free(data_rx[i].payload);
} }
} }
for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) { for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) {

@ -26,16 +26,16 @@
#include "srslte/phy/phch/uci_cfg.h" #include "srslte/phy/phch/uci_cfg.h"
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
#include <inttypes.h>
#define UCI_NR_INFO_TX(...) INFO("UCI-NR Tx: " __VA_ARGS__) #define UCI_NR_INFO_TX(...) INFO("UCI-NR Tx: " __VA_ARGS__)
#define UCI_NR_INFO_RX(...) INFO("UCI-NR Rx: " __VA_ARGS__) #define UCI_NR_INFO_RX(...) INFO("UCI-NR Rx: " __VA_ARGS__)
#define UCI_NR_MAX_L 11U #define UCI_NR_MAX_L 11U
#define UCI_NR_POLAR_MAX 2048U #define UCI_NR_POLAR_MAX 2048U
#define UCI_NR_POLAR_RM_IBIL 0 #define UCI_NR_POLAR_RM_IBIL 1
#define UCI_NR_PUCCH_POLAR_N_MAX 10 #define UCI_NR_PUCCH_POLAR_N_MAX 10
#define UCI_NR_BLOCK_DEFAULT_CORR_THRESHOLD 0.5f #define UCI_NR_BLOCK_DEFAULT_CORR_THRESHOLD 0.5f
#define UCI_NR_ONE_BIT_CORR_THRESHOLD 0.5f
uint32_t srslte_uci_nr_crc_len(uint32_t A) uint32_t srslte_uci_nr_crc_len(uint32_t A)
{ {
@ -123,6 +123,11 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args)
} else { } else {
q->block_code_threshold = UCI_NR_BLOCK_DEFAULT_CORR_THRESHOLD; q->block_code_threshold = UCI_NR_BLOCK_DEFAULT_CORR_THRESHOLD;
} }
if (isnormal(args->one_bit_threshold)) {
q->one_bit_threshold = args->one_bit_threshold;
} else {
q->one_bit_threshold = UCI_NR_ONE_BIT_CORR_THRESHOLD;
}
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -199,7 +204,7 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequenc
static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg)
{ {
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); int o_csi = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (o_csi == 0) { if (o_csi == 0) {
@ -216,9 +221,9 @@ static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) static int uci_nr_pack_pucch(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence)
{ {
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); int o_csi = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (o_csi == 0) { if (o_csi == 0) {
@ -235,9 +240,9 @@ static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) static int uci_nr_unpack_pucch(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value)
{ {
int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); int o_csi = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
// 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation
if (o_csi == 0) { if (o_csi == 0) {
@ -260,7 +265,7 @@ static int uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
uint32_t i = 0; uint32_t i = 0;
srslte_uci_bit_type_t c0 = (q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1; srslte_uci_bit_type_t c0 = (q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1;
switch (cfg->modulation) { switch (cfg->pusch.modulation) {
case SRSLTE_MOD_BPSK: case SRSLTE_MOD_BPSK:
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
@ -269,39 +274,39 @@ static int uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
case SRSLTE_MOD_QPSK: case SRSLTE_MOD_QPSK:
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_REPETITION; o[i++] = (uint8_t)UCI_BIT_REPETITION;
} }
break; break;
case SRSLTE_MOD_16QAM: case SRSLTE_MOD_16QAM:
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_REPETITION; o[i++] = (uint8_t)UCI_BIT_REPETITION;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
break; break;
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
while (i < E) { while (i < E) {
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_REPETITION; o[i++] = (uint8_t)UCI_BIT_REPETITION;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
} }
break; break;
case SRSLTE_MOD_256QAM: case SRSLTE_MOD_256QAM:
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_REPETITION; o[i++] = (uint8_t)UCI_BIT_REPETITION;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
break; break;
case SRSLTE_MOD_NITEMS: case SRSLTE_MOD_NITEMS:
@ -310,17 +315,69 @@ static int uci_nr_encode_1bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("One bit encoded NR-UCI; o=");
srslte_vec_fprint_b(stdout, o, E);
}
return E; return E;
} }
static int uci_nr_decode_1_bit(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
uint32_t A,
const int8_t* llr,
uint32_t E,
bool* decoded_ok)
{
uint32_t Qm = srslte_mod_bits_x_symbol(cfg->pusch.modulation);
if (Qm == 0) {
ERROR("Invalid modulation (%s)", srslte_mod_string(cfg->pusch.modulation));
return SRSLTE_ERROR;
}
// Correlate LLR
float corr = 0.0f;
float pwr = 0.0f;
for (uint32_t i = 0; i < E; i += Qm) {
float t = (float)llr[i];
corr += t;
pwr += t * t;
}
// Normalise correlation
float norm_corr = Qm * corr / (E * sqrtf(pwr));
// Take decoded decision with threshold
*decoded_ok = (norm_corr > q->one_bit_threshold);
// Save decoded bit
q->bit_sequence[0] = (corr < 0) ? 0 : 1;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("One bit decoding NR-UCI llr=");
srslte_vec_fprint_bs(stdout, llr, E);
UCI_NR_INFO_RX("One bit decoding NR-UCI A=%d; E=%d; pwr=%f; corr=%f; norm=%f; thr=%f; %s",
A,
E,
pwr,
corr,
norm_corr,
q->block_code_threshold,
*decoded_ok ? "OK" : "KO");
}
return SRSLTE_SUCCESS;
}
static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint8_t* o, uint32_t E) static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint8_t* o, uint32_t E)
{ {
uint32_t i = 0; uint32_t i = 0;
srslte_uci_bit_type_t c0 = (q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1; uint8_t c0 = (uint8_t)((q->bit_sequence[0] == 0) ? UCI_BIT_0 : UCI_BIT_1);
srslte_uci_bit_type_t c1 = (q->bit_sequence[1] == 0) ? UCI_BIT_0 : UCI_BIT_1; uint8_t c1 = (uint8_t)((q->bit_sequence[1] == 0) ? UCI_BIT_0 : UCI_BIT_1);
srslte_uci_bit_type_t c2 = ((q->bit_sequence[0] ^ q->bit_sequence[1]) == 0) ? UCI_BIT_0 : UCI_BIT_1; uint8_t c2 = (uint8_t)(((q->bit_sequence[0] ^ q->bit_sequence[1]) == 0) ? UCI_BIT_0 : UCI_BIT_1);
switch (cfg->modulation) { switch (cfg->pusch.modulation) {
case SRSLTE_MOD_BPSK: case SRSLTE_MOD_BPSK:
case SRSLTE_MOD_QPSK: case SRSLTE_MOD_QPSK:
while (i < E) { while (i < E) {
@ -333,38 +390,38 @@ static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = c1; o[i++] = c1;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c2; o[i++] = c2;
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c1; o[i++] = c1;
o[i++] = c2; o[i++] = c2;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
break; break;
case SRSLTE_MOD_64QAM: case SRSLTE_MOD_64QAM:
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = c1; o[i++] = c1;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c2; o[i++] = c2;
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c1; o[i++] = c1;
o[i++] = c2; o[i++] = c2;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
break; break;
case SRSLTE_MOD_256QAM: case SRSLTE_MOD_256QAM:
@ -372,28 +429,28 @@ static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
while (i < E) { while (i < E) {
o[i++] = c0; o[i++] = c0;
o[i++] = c1; o[i++] = c1;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c2; o[i++] = c2;
o[i++] = c0; o[i++] = c0;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = c1; o[i++] = c1;
o[i++] = c2; o[i++] = c2;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
o[i++] = UCI_BIT_PLACEHOLDER; o[i++] = (uint8_t)UCI_BIT_PLACEHOLDER;
} }
break; break;
case SRSLTE_MOD_NITEMS: case SRSLTE_MOD_NITEMS:
@ -402,9 +459,68 @@ static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Two bit encoded NR-UCI; E=%d; o=", E);
srslte_vec_fprint_b(stdout, o, E);
}
return E; return E;
} }
static int uci_nr_decode_2_bit(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
uint32_t A,
const int8_t* llr,
uint32_t E,
bool* decoded_ok)
{
uint32_t Qm = srslte_mod_bits_x_symbol(cfg->pusch.modulation);
if (Qm == 0) {
ERROR("Invalid modulation (%s)", srslte_mod_string(cfg->pusch.modulation));
return SRSLTE_ERROR;
}
// Correlate LLR
float corr[3] = {};
if (Qm == 1) {
for (uint32_t i = 0; i < E / Qm; i++) {
corr[i % 3] = llr[i];
}
} else {
for (uint32_t i = 0, j = 0; i < E; i += Qm) {
corr[(j++) % 3] = llr[i + 0];
corr[(j++) % 3] = llr[i + 1];
}
}
// Take decoded decision
bool c0 = corr[0] > 0.0f;
bool c1 = corr[1] > 0.0f;
bool c2 = corr[2] > 0.0f;
// Check redundancy bit
*decoded_ok = (c2 == (c0 ^ c1));
// Save decoded bits
q->bit_sequence[0] = c0 ? 1 : 0;
q->bit_sequence[1] = c1 ? 1 : 0;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Two bit decoding NR-UCI llr=");
srslte_vec_fprint_bs(stdout, llr, E);
UCI_NR_INFO_RX("Two bit decoding NR-UCI A=%d; E=%d; Qm=%d; c0=%d; c1=%d; c2=%d %s",
A,
E,
Qm,
c0,
c1,
c2,
*decoded_ok ? "OK" : "KO");
}
return SRSLTE_SUCCESS;
}
static int static int
uci_nr_encode_3_11_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E) uci_nr_encode_3_11_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E)
{ {
@ -438,6 +554,7 @@ static int uci_nr_decode_3_11_bit(srslte_uci_nr_t* q,
// Compute average LLR power // Compute average LLR power
float pwr = srslte_vec_avg_power_bf(llr, E); float pwr = srslte_vec_avg_power_bf(llr, E);
if (!isnormal(pwr)) { if (!isnormal(pwr)) {
ERROR("Received all zeros");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -466,8 +583,6 @@ static int uci_nr_decode_3_11_bit(srslte_uci_nr_t* q,
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
static int static int
uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E_uci) uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E_uci)
{ {
@ -486,12 +601,13 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
if (I_seg == 1) { if (I_seg == 1) {
C = 2; C = 2;
} }
uint32_t A_prime = CEIL(A, C) * C; uint32_t A_prime = SRSLTE_CEIL(A, C) * C;
// Get polar code // Get polar code
uint32_t K_r = A_prime / C + L; uint32_t K_r = A_prime / C + L;
uint32_t E_r = E_uci / C; uint32_t E_r = E_uci / C;
if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) { if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) {
ERROR("Error computing Polar code");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -533,12 +649,17 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Polar encoded %d/%d ", r, C);
srslte_vec_fprint_byte(stdout, q->d, q->code.N);
}
// Rate matching // Rate matching
srslte_polar_rm_tx(&q->rm_tx, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL); srslte_polar_rm_tx(&q->rm_tx, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Polar cw %d/%d ", r, C); UCI_NR_INFO_TX("Polar RM cw %d/%d ", r, C);
srslte_vec_fprint_byte(stdout, &o[E_r * r], q->code.N); srslte_vec_fprint_byte(stdout, &o[E_r * r], E_r);
} }
} }
@ -569,7 +690,7 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
if (I_seg == 1) { if (I_seg == 1) {
C = 2; C = 2;
} }
uint32_t A_prime = CEIL(A, C) * C; uint32_t A_prime = SRSLTE_CEIL(A, C) * C;
// Get polar code // Get polar code
uint32_t K_r = A_prime / C + L; uint32_t K_r = A_prime / C + L;
@ -638,23 +759,8 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
static int uci_nr_encode(srslte_uci_nr_t* q, static int uci_nr_encode(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t A, uint8_t* o, uint32_t E_uci)
const srslte_uci_cfg_nr_t* uci_cfg,
const srslte_uci_value_nr_t* uci_value,
uint8_t* o,
uint32_t E_uci)
{ {
if (q == NULL || uci_cfg == NULL || uci_value == NULL || o == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// 6.3.1.1 UCI bit sequence generation
int A = uci_nr_packing(uci_cfg, uci_value, q->bit_sequence);
if (A < SRSLTE_SUCCESS) {
ERROR("Generating bit sequence");
return SRSLTE_ERROR;
}
// 5.3.3.1 Encoding of 1-bit information // 5.3.3.1 Encoding of 1-bit information
if (A == 1) { if (A == 1) {
return uci_nr_encode_1bit(q, uci_cfg, o, E_uci); return uci_nr_encode_1bit(q, uci_cfg, o, E_uci);
@ -681,42 +787,35 @@ static int uci_nr_encode(srslte_uci_nr_t* q,
static int uci_nr_decode(srslte_uci_nr_t* q, static int uci_nr_decode(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* uci_cfg, const srslte_uci_cfg_nr_t* uci_cfg,
int8_t* llr, int8_t* llr,
uint32_t A,
uint32_t E_uci, uint32_t E_uci,
srslte_uci_value_nr_t* uci_value) bool* valid)
{ {
if (q == NULL || uci_cfg == NULL || uci_value == NULL || llr == NULL) { if (q == NULL || uci_cfg == NULL || valid == NULL || llr == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
// 6.3.1.1 UCI bit sequence generation
int A = uci_nr_A(uci_cfg);
if (A < SRSLTE_SUCCESS) {
ERROR("Error getting number of bits");
return SRSLTE_ERROR;
}
// Decode LLR // Decode LLR
if (A == 1) { if (A == 1) {
ERROR("Not implemented"); if (uci_nr_decode_1_bit(q, uci_cfg, A, llr, E_uci, valid) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
} else if (A == 2) { } else if (A == 2) {
ERROR("Not implemented"); if (uci_nr_decode_2_bit(q, uci_cfg, A, llr, E_uci, valid) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
} else if (A <= 11) { } else if (A <= 11) {
if (uci_nr_decode_3_11_bit(q, uci_cfg, A, llr, E_uci, &uci_value->valid) < SRSLTE_SUCCESS) { if (uci_nr_decode_3_11_bit(q, uci_cfg, A, llr, E_uci, valid) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} else if (A < SRSLTE_UCI_NR_MAX_NOF_BITS) { } else if (A < SRSLTE_UCI_NR_MAX_NOF_BITS) {
if (uci_nr_decode_11_1706_bit(q, uci_cfg, A, llr, E_uci, &uci_value->valid) < SRSLTE_SUCCESS) { if (uci_nr_decode_11_1706_bit(q, uci_cfg, A, llr, E_uci, valid) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} else { } else {
ERROR("Invalid number of bits (A=%d)", A); ERROR("Invalid number of bits (A=%d)", A);
} }
// Unpack bits
if (uci_nr_unpacking(uci_cfg, q->bit_sequence, uci_value) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -779,7 +878,14 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return uci_nr_encode(q, uci_cfg, value, o, E_uci); // 6.3.1.1 UCI bit sequence generation
int A = uci_nr_pack_pucch(uci_cfg, value, q->bit_sequence);
if (A < SRSLTE_SUCCESS) {
ERROR("Generating bit sequence");
return SRSLTE_ERROR;
}
return uci_nr_encode(q, uci_cfg, A, o, E_uci);
} }
int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q, int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
@ -795,10 +901,29 @@ int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot); int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot);
if (E_uci < SRSLTE_SUCCESS) { if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of encoded PUCCH UCI bits");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return uci_nr_decode(q, uci_cfg, llr, E_uci, value); // 6.3.1.1 UCI bit sequence generation
int A = uci_nr_A(uci_cfg);
if (A < SRSLTE_SUCCESS) {
ERROR("Error getting number of bits");
return SRSLTE_ERROR;
}
if (uci_nr_decode(q, uci_cfg, llr, A, E_uci, &value->valid) < SRSLTE_SUCCESS) {
ERROR("Error decoding UCI bits");
return SRSLTE_ERROR;
}
// Unpack bits
if (uci_nr_unpack_pucch(uci_cfg, q->bit_sequence, value) < SRSLTE_SUCCESS) {
ERROR("Error unpacking PUCCH UCI bits");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
} }
uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg) uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg)
@ -807,14 +932,14 @@ uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg)
return 0; return 0;
} }
return uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); return uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
} }
uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len) uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len)
{ {
uint32_t len = 0; uint32_t len = 0;
len = srslte_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.rnti); len = srslte_print_check(str, str_len, len, "rnti=0x%x", uci_data->cfg.pucch.rnti);
if (uci_data->cfg.o_ack > 0) { if (uci_data->cfg.o_ack > 0) {
char str2[10]; char str2[10];
@ -832,3 +957,257 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin
return len; return len;
} }
static int uci_nr_pusch_Q_prime_ack(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack)
{
if (cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
uint32_t L_ack = srslte_uci_nr_crc_len(O_ack); // Number of CRC bits
uint32_t Qm = srslte_mod_bits_x_symbol(cfg->modulation); // modulation order of the PUSCH
uint32_t M_uci_sum = 0;
uint32_t M_uci_l0_sum = 0;
for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) {
M_uci_sum += cfg->M_uci_sc[l];
if (l >= cfg->l0) {
M_uci_l0_sum += cfg->M_uci_sc[l];
}
}
if (!isnormal(cfg->R)) {
ERROR("Invalid Rate (%f)", cfg->R);
return SRSLTE_ERROR;
}
if (cfg->K_sum == 0) {
return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * cfg->beta_harq_ack_offset) / (Qm * cfg->R)),
cfg->alpha * M_uci_l0_sum);
}
return (int)SRSLTE_MIN(ceilf(((O_ack + L_ack) * cfg->beta_harq_ack_offset * M_uci_sum) / cfg->K_sum),
cfg->alpha * M_uci_l0_sum);
}
int srslte_uci_nr_pusch_ack_nof_bits(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack)
{
// Check inputs
if (cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (cfg->nof_layers == 0) {
ERROR("Invalid number of layers (%d)", cfg->nof_layers);
return SRSLTE_ERROR;
}
int Q_ack_prime = uci_nr_pusch_Q_prime_ack(cfg, O_ack);
if (Q_ack_prime < SRSLTE_SUCCESS) {
ERROR("Error calculating number of RE");
return Q_ack_prime;
}
return (int)(Q_ack_prime * cfg->nof_layers * srslte_mod_bits_x_symbol(cfg->modulation));
}
int srslte_uci_nr_encode_pusch_ack(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o)
{
int A = cfg->o_ack;
// Check inputs
if (q == NULL || cfg == NULL || value == NULL || o == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// 6.3.2.1 UCI bit sequence generation
// 6.3.2.1.1 HARQ-ACK
bool has_csi_part2 = srslte_csi_has_part2(cfg->csi, cfg->nof_csi);
if (cfg->pusch.K_sum == 0 && cfg->nof_csi > 1 && !has_csi_part2 && A < 2) {
q->bit_sequence[0] = (A == 0) ? 0 : value->ack[0];
q->bit_sequence[1] = 0;
A = 2;
} else if (A == 0) {
UCI_NR_INFO_TX("No HARQ-ACK to mux");
return SRSLTE_SUCCESS;
} else {
srslte_vec_u8_copy(q->bit_sequence, value->ack, cfg->o_ack);
}
// Compute total of encoded bits according to 6.3.2.4 Rate matching
int E_uci = srslte_uci_nr_pusch_ack_nof_bits(&cfg->pusch, A);
if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of encoded bits");
return SRSLTE_ERROR;
}
return uci_nr_encode(q, cfg, A, o, E_uci);
}
int srslte_uci_nr_decode_pusch_ack(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
int8_t* llr,
srslte_uci_value_nr_t* value)
{
int A = cfg->o_ack;
// Check inputs
if (q == NULL || cfg == NULL || llr == NULL || value == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// 6.3.2.1 UCI bit sequence generation
// 6.3.2.1.1 HARQ-ACK
bool has_csi_part2 = srslte_csi_has_part2(cfg->csi, cfg->nof_csi);
if (cfg->pusch.K_sum == 0 && cfg->nof_csi > 1 && !has_csi_part2 && cfg->o_ack < 2) {
A = 2;
}
// Compute total of encoded bits according to 6.3.2.4 Rate matching
int E_uci = srslte_uci_nr_pusch_ack_nof_bits(&cfg->pusch, A);
if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of encoded bits");
return SRSLTE_ERROR;
}
// Decode
if (uci_nr_decode(q, cfg, llr, A, E_uci, &value->valid) < SRSLTE_SUCCESS) {
ERROR("Error decoding UCI");
return SRSLTE_ERROR;
}
// Unpack
srslte_vec_u8_copy(value->ack, q->bit_sequence, A);
return SRSLTE_SUCCESS;
}
static int uci_nr_pusch_Q_prime_csi1(const srslte_uci_nr_pusch_cfg_t* cfg, uint32_t O_csi1, uint32_t O_ack)
{
if (cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
uint32_t L_ack = srslte_uci_nr_crc_len(O_csi1); // Number of CRC bits
uint32_t Qm = srslte_mod_bits_x_symbol(cfg->modulation); // modulation order of the PUSCH
int Q_prime_ack = uci_nr_pusch_Q_prime_ack(cfg, SRSLTE_MAX(2, O_ack));
if (Q_prime_ack < SRSLTE_ERROR) {
ERROR("Calculating Q_prime_ack");
return SRSLTE_ERROR;
}
uint32_t M_uci_sum = 0;
for (uint32_t l = 0; l < SRSLTE_NSYMB_PER_SLOT_NR; l++) {
M_uci_sum += cfg->M_uci_sc[l];
}
if (!isnormal(cfg->R)) {
ERROR("Invalid Rate (%f)", cfg->R);
return SRSLTE_ERROR;
}
if (cfg->K_sum == 0) {
if (cfg->csi_part2_present) {
return (int)SRSLTE_MIN(ceilf(((O_csi1 + L_ack) * cfg->beta_csi1_offset) / (Qm * cfg->R)),
cfg->alpha * M_uci_sum - Q_prime_ack);
}
return (int)(M_uci_sum - Q_prime_ack);
}
return (int)SRSLTE_MIN(ceilf(((O_csi1 + L_ack) * cfg->beta_csi1_offset * M_uci_sum) / cfg->K_sum),
ceilf(cfg->alpha * M_uci_sum) - Q_prime_ack);
}
int srslte_uci_nr_pusch_csi1_nof_bits(const srslte_uci_cfg_nr_t* cfg)
{
// Check inputs
if (cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
int O_csi1 = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
if (O_csi1 < SRSLTE_SUCCESS) {
ERROR("Errpr calculating CSI part 1 number of bits");
return SRSLTE_ERROR;
}
uint32_t O_ack = SRSLTE_MAX(2, cfg->o_ack);
int Q_csi1_prime = uci_nr_pusch_Q_prime_csi1(&cfg->pusch, (uint32_t)O_csi1, O_ack);
if (Q_csi1_prime < SRSLTE_SUCCESS) {
ERROR("Error calculating number of RE");
return Q_csi1_prime;
}
return (int)(Q_csi1_prime * cfg->pusch.nof_layers * srslte_mod_bits_x_symbol(cfg->pusch.modulation));
}
int srslte_uci_nr_encode_pusch_csi1(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o)
{
// Check inputs
if (q == NULL || cfg == NULL || value == NULL || o == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
int A = srslte_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, q->bit_sequence, SRSLTE_UCI_NR_MAX_NOF_BITS);
if (A < SRSLTE_SUCCESS) {
ERROR("Error packing CSI part 1 report");
return SRSLTE_ERROR;
}
if (A == 0) {
UCI_NR_INFO_TX("No CSI part 1 to mux");
return SRSLTE_SUCCESS;
}
// Compute total of encoded bits according to 6.3.2.4 Rate matching
int E_uci = srslte_uci_nr_pusch_csi1_nof_bits(cfg);
if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of encoded bits");
return SRSLTE_ERROR;
}
return uci_nr_encode(q, cfg, A, o, E_uci);
}
int srslte_uci_nr_decode_pusch_csi1(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
int8_t* llr,
srslte_uci_value_nr_t* value)
{
// Check inputs
if (q == NULL || cfg == NULL || llr == NULL || value == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Compute total of encoded bits according to 6.3.2.4 Rate matching
int E_uci = srslte_uci_nr_pusch_csi1_nof_bits(cfg);
if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of encoded bits");
return SRSLTE_ERROR;
}
int A = srslte_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
if (A < SRSLTE_SUCCESS) {
ERROR("Error getting number of CSI part 1 bits");
return SRSLTE_ERROR;
}
// Decode
if (uci_nr_decode(q, cfg, llr, (uint32_t)A, (uint32_t)E_uci, &value->valid) < SRSLTE_SUCCESS) {
ERROR("Error decoding UCI");
return SRSLTE_ERROR;
}
// Unpack
if (srslte_csi_part1_unpack(cfg->csi, cfg->nof_csi, q->bit_sequence, A, value->csi) < SRSLTE_SUCCESS) {
ERROR("Error unpacking CSI");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}

@ -583,8 +583,8 @@ static int ue_dl_nr_gen_ack_type2(const srslte_ue_dl_nr_harq_ack_cfg_t* cfg,
} else { } else {
if (ack->present) { if (ack->present) {
// Load ACK resource data into UCI info // Load ACK resource data into UCI info
uci_data->cfg.pucch_resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id; uci_data->cfg.pucch.resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id;
uci_data->cfg.rnti = ack_info->cc[c].m[m].resource.rnti; uci_data->cfg.pucch.rnti = ack_info->cc[c].m[m].resource.rnti;
if (V_DL_CDAI <= V_temp) { if (V_DL_CDAI <= V_temp) {
j = j + 1; j = j + 1;

@ -91,6 +91,11 @@ int srslte_ue_ul_nr_set_carrier(srslte_ue_ul_nr_t* q, const srslte_carrier_nr_t*
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_pucch_nr_set_carrier(&q->pucch, carrier) < SRSLTE_SUCCESS) {
ERROR("Setting PUSCH carrier");
return SRSLTE_ERROR;
}
if (srslte_dmrs_sch_set_carrier(&q->dmrs, carrier)) { if (srslte_dmrs_sch_set_carrier(&q->dmrs, carrier)) {
ERROR("Setting DMRS carrier"); ERROR("Setting DMRS carrier");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -99,16 +104,13 @@ int srslte_ue_ul_nr_set_carrier(srslte_ue_ul_nr_t* q, const srslte_carrier_nr_t*
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q, int srslte_ue_ul_nr_encode_pusch(srslte_ue_ul_nr_t* q,
const srslte_slot_cfg_t* slot_cfg, const srslte_slot_cfg_t* slot_cfg,
const srslte_sch_cfg_nr_t* pusch_cfg, const srslte_sch_cfg_nr_t* pusch_cfg,
uint8_t* data_) const srslte_pusch_data_nr_t* data)
{ {
uint8_t* data[SRSLTE_MAX_TB] = {};
data[0] = data_;
// Check inputs // Check inputs
if (q == NULL || pusch_cfg == NULL || data_ == NULL) { if (q == NULL || pusch_cfg == NULL || data == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -167,7 +169,7 @@ static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return srslte_pucch_nr_format1_encode(&q->pucch, &q->carrier, cfg, slot, resource, b, nof_bits, q->sf_symbols[0]); return srslte_pucch_nr_format1_encode(&q->pucch, cfg, slot, resource, b, nof_bits, q->sf_symbols[0]);
} }
int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q, int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q,
@ -201,7 +203,7 @@ int srslte_ue_ul_nr_encode_pucch(srslte_ue_ul_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_pucch_nr_format_2_3_4_encode( if (srslte_pucch_nr_format_2_3_4_encode(
&q->pucch, &q->carrier, cfg, slot_cfg, resource, &uci_data->cfg, &uci_data->value, q->sf_symbols[0]) < &q->pucch, cfg, slot_cfg, resource, &uci_data->cfg, &uci_data->value, q->sf_symbols[0]) <
SRSLTE_SUCCESS) { SRSLTE_SUCCESS) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -20,6 +20,7 @@
*/ */
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/common/standard_streams.h"
#include "srslte/common/string_helpers.h" #include "srslte/common/string_helpers.h"
#include "srslte/config.h" #include "srslte/config.h"
#include <list> #include <list>
@ -297,10 +298,13 @@ bool radio::rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time
if (ratio > 1 && nof_samples > rx_buffer[0].size()) { if (ratio > 1 && nof_samples > rx_buffer[0].size()) {
// This is a corner case that could happen during sample rate change transitions, as it does not have a negative // This is a corner case that could happen during sample rate change transitions, as it does not have a negative
// impact, log it as info. // impact, log it as info.
logger.info(fmt::format("Rx number of samples ({}/{}) exceeds buffer size ({})\n", fmt::memory_buffer buff;
buffer.get_nof_samples(), fmt::format_to(buff,
buffer.get_nof_samples() * ratio, "Rx number of samples ({}/{}) exceeds buffer size ({})",
rx_buffer[0].size())); buffer.get_nof_samples(),
buffer.get_nof_samples() * ratio,
rx_buffer[0].size());
logger.info("%s", to_c_str(buff));
// Limit number of samples to receive // Limit number of samples to receive
nof_samples = rx_buffer[0].size(); nof_samples = rx_buffer[0].size();
@ -415,10 +419,13 @@ bool radio::tx(rf_buffer_interface& buffer, const rf_timestamp_interface& tx_tim
if (ratio > 1 && nof_samples * ratio > tx_buffer[0].size()) { if (ratio > 1 && nof_samples * ratio > tx_buffer[0].size()) {
// This is a corner case that could happen during sample rate change transitions, as it does not have a negative // This is a corner case that could happen during sample rate change transitions, as it does not have a negative
// impact, log it as info. // impact, log it as info.
logger.info(fmt::format("Tx number of samples ({}/{}) exceeds buffer size ({})\n", fmt::memory_buffer buff;
buffer.get_nof_samples(), fmt::format_to(buff,
buffer.get_nof_samples() * ratio, "Tx number of samples ({}/{}) exceeds buffer size ({})\n",
tx_buffer[0].size())); buffer.get_nof_samples(),
buffer.get_nof_samples() * ratio,
tx_buffer[0].size());
logger.info("%s", to_c_str(buff));
// Limit number of samples to transmit // Limit number of samples to transmit
nof_samples = tx_buffer[0].size() / ratio; nof_samples = tx_buffer[0].size() / ratio;

@ -97,14 +97,11 @@ void backend_worker::process_log_entry(detail::log_entry&& entry)
return; return;
} }
fmt::memory_buffer fmt_buffer;
assert(entry.format_func && "Invalid format function"); assert(entry.format_func && "Invalid format function");
fmt_buffer.clear();
entry.format_func(std::move(entry.metadata), fmt_buffer); entry.format_func(std::move(entry.metadata), fmt_buffer);
const auto str = fmt::to_string(fmt_buffer); if (auto err_str = entry.s->write({fmt_buffer.data(), fmt_buffer.size()})) {
detail::memory_buffer buffer(str);
if (auto err_str = entry.s->write(buffer)) {
err_handler(err_str.get_error()); err_handler(err_str.get_error());
} }
} }

@ -120,6 +120,7 @@ private:
}; };
std::once_flag start_once_flag; std::once_flag start_once_flag;
std::thread worker_thread; std::thread worker_thread;
fmt::memory_buffer fmt_buffer;
}; };
} // namespace srslog } // namespace srslog

@ -20,6 +20,7 @@
*/ */
#include "srslte/srslog/event_trace.h" #include "srslte/srslog/event_trace.h"
#include "sinks/single_write_file_sink.h"
#include "srslte/srslog/srslog.h" #include "srslte/srslog/srslog.h"
#include <ctime> #include <ctime>
@ -32,6 +33,9 @@ using namespace srslog;
/// Log channel where event traces will get sent. /// Log channel where event traces will get sent.
static log_channel* tracer = nullptr; static log_channel* tracer = nullptr;
/// Tracer sink name.
static constexpr char sink_name[] = "srslog_trace_sink";
void srslog::event_trace_init() void srslog::event_trace_init()
{ {
// Nothing to do if the user previously set a custom channel or this is not // Nothing to do if the user previously set a custom channel or this is not
@ -59,6 +63,30 @@ void srslog::event_trace_init(log_channel& c)
} }
} }
bool srslog::event_trace_init(const std::string& filename, std::size_t capacity)
{
// Nothing to do if the user previously set a custom channel or this is not
// the first time this function is called.
if (tracer) {
return false;
}
auto tracer_sink = std::unique_ptr<sink>(new single_write_file_sink(
filename, capacity, get_default_log_formatter()));
if (!install_custom_sink(sink_name, std::move(tracer_sink))) {
return false;
}
if (sink* s = find_sink(sink_name)) {
log_channel& c =
fetch_log_channel("event_trace_channel", *s, {"TRACE", '\0', false});
tracer = &c;
return true;
}
return false;
}
/// Fills in the input buffer with the current time. /// Fills in the input buffer with the current time.
static void format_time(char* buffer, size_t len) static void format_time(char* buffer, size_t len)
{ {
@ -113,10 +141,7 @@ srslog::detail::scoped_complete_event::~scoped_complete_event()
std::chrono::duration_cast<std::chrono::microseconds>(end - start) std::chrono::duration_cast<std::chrono::microseconds>(end - start)
.count(); .count();
char fmt_time[24]; (*tracer)("[TID:%0u] Complete event \"%s\" (duration %lld us): %s",
format_time(fmt_time, sizeof(fmt_time));
(*tracer)("[%s] [TID:%0u] Complete event \"%s\" (duration %lld us): %s",
fmt_time,
(unsigned)::pthread_self(), (unsigned)::pthread_self(),
category, category,
diff, diff,

@ -58,7 +58,7 @@ void json_formatter::format_context_begin(const detail::log_entry_metadata& md,
fmt::format_to(buffer, "{{\n"); fmt::format_to(buffer, "{{\n");
push_scope(size); push_scope(size);
if (!md.fmtstring.empty()) { if (md.fmtstring) {
fmt::format_to(buffer, fmt::format_to(buffer,
" \"log_entry\": \"{}\",\n", " \"log_entry\": \"{}\",\n",
fmt::vsprintf(md.fmtstring, std::move(md.store))); fmt::vsprintf(md.fmtstring, std::move(md.store)));

@ -99,13 +99,16 @@ void text_formatter::format_context_begin(const detail::log_entry_metadata& md,
unsigned size, unsigned size,
fmt::memory_buffer& buffer) fmt::memory_buffer& buffer)
{ {
do_one_line_ctx_format = !md.fmtstring.empty(); // Entries without a log message are printed using a richer format.
do_one_line_ctx_format = md.fmtstring;
format_metadata(md, buffer); format_metadata(md, buffer);
if (do_one_line_ctx_format) { if (do_one_line_ctx_format) {
assert(scope_stack.empty() && "Stack should be empty");
fmt::format_to(buffer, "["); fmt::format_to(buffer, "[");
return; return;
} }
fmt::format_to(buffer, "Context dump for \"{}\"\n", ctx_name); fmt::format_to(buffer, "Context dump for \"{}\"\n", ctx_name);
} }
@ -113,10 +116,12 @@ void text_formatter::format_context_end(const detail::log_entry_metadata& md,
const std::string& ctx_name, const std::string& ctx_name,
fmt::memory_buffer& buffer) fmt::memory_buffer& buffer)
{ {
if (do_one_line_ctx_format) { if (!do_one_line_ctx_format) {
fmt::format_to(buffer, "]: {}\n", fmt::vsprintf(md.fmtstring, md.store));
return; return;
} }
fmt::format_to(buffer, "]: {}\n", fmt::vsprintf(md.fmtstring, md.store));
assert(scope_stack.empty() && "Stack should be empty");
} }
void text_formatter::format_metric_set_begin(const std::string& set_name, void text_formatter::format_metric_set_begin(const std::string& set_name,
@ -124,21 +129,26 @@ void text_formatter::format_metric_set_begin(const std::string& set_name,
unsigned level, unsigned level,
fmt::memory_buffer& buffer) fmt::memory_buffer& buffer)
{ {
/*if (do_one_line_ctx_format) { if (do_one_line_ctx_format) {
fmt::format_to(buffer, "{}", is_first ? "[" : " ["); scope_stack.emplace_back(size, set_name);
fmt::format_to(buffer, "[");
return; return;
} }
fmt::format_to(buffer, " {}\n", set_name);*/
fmt::format_to(
buffer, "{: <{}}> Set: {}\n", ' ', get_indents(level), set_name);
} }
void text_formatter::format_metric_set_end(const std::string& set_name, void text_formatter::format_metric_set_end(const std::string& set_name,
unsigned level, unsigned level,
fmt::memory_buffer& buffer) fmt::memory_buffer& buffer)
{ {
if (do_one_line_ctx_format) { if (!do_one_line_ctx_format) {
fmt::format_to(buffer, "]");
return; return;
} }
scope_stack.pop_back();
fmt::format_to(buffer, "]");
} }
void text_formatter::format_metric(const std::string& metric_name, void text_formatter::format_metric(const std::string& metric_name,
@ -148,22 +158,37 @@ void text_formatter::format_metric(const std::string& metric_name,
unsigned level, unsigned level,
fmt::memory_buffer& buffer) fmt::memory_buffer& buffer)
{ {
//:TODO: re-enable if (do_one_line_ctx_format) {
/*if (do_one_line_ctx_format) { consume_element();
fmt::format_to(buffer, fmt::format_to(buffer,
"{}{}_{}: {}{}{}", "{}_{}: {}{}{}{}",
ctx.is_first_metric ? "" : ", ", get_current_set_name(),
ctx.set_name, metric_name,
ctx.metric_name, metric_value,
ctx.metric_value, metric_units.empty() ? "" : " ",
ctx.metric_units.empty() ? "" : " ", metric_units,
ctx.metric_units); needs_comma() ? ", " : "");
return; return;
} }
fmt::format_to(buffer, fmt::format_to(buffer,
" {}: {}{}{}\n", "{: <{}}{}: {}{}{}\n",
ctx.metric_name, ' ',
ctx.metric_value, get_indents(level),
ctx.metric_units.empty() ? "" : " ", metric_name,
ctx.metric_units);*/ metric_value,
metric_units.empty() ? "" : " ",
metric_units);
}
void text_formatter::format_list_begin(const std::string& list_name,
unsigned size,
unsigned level,
fmt::memory_buffer& buffer)
{
if (do_one_line_ctx_format) {
return;
}
fmt::format_to(
buffer, "{: <{}}> List: {}\n", ' ', get_indents(level), list_name);
} }

@ -27,11 +27,11 @@
namespace srslog { namespace srslog {
/// Plain text formatter implementation class. /// Plain text formatter implementation class.
//:TODO: this class needs refactoring to be compatible with multiple nesting of
// metrics.
class text_formatter : public log_formatter class text_formatter : public log_formatter
{ {
public: public:
text_formatter() { scope_stack.reserve(16); }
std::unique_ptr<log_formatter> clone() const override; std::unique_ptr<log_formatter> clone() const override;
void format(detail::log_entry_metadata&& metadata, void format(detail::log_entry_metadata&& metadata,
@ -59,17 +59,12 @@ private:
void format_list_begin(const std::string& list_name, void format_list_begin(const std::string& list_name,
unsigned size, unsigned size,
unsigned level, unsigned level,
fmt::memory_buffer& buffer) override fmt::memory_buffer& buffer) override;
{
//:TODO: implement me
}
void format_list_end(const std::string& list_name, void format_list_end(const std::string& list_name,
unsigned level, unsigned level,
fmt::memory_buffer& buffer) override fmt::memory_buffer& buffer) override
{ {}
//:TODO: implement me
}
void format_metric(const std::string& metric_name, void format_metric(const std::string& metric_name,
const std::string& metric_value, const std::string& metric_value,
@ -78,9 +73,47 @@ private:
unsigned level, unsigned level,
fmt::memory_buffer& buffer) override; fmt::memory_buffer& buffer) override;
/// Returns the set name of current scope.
const std::string& get_current_set_name() const
{
assert(!scope_stack.empty() && "Empty scope stack");
return scope_stack.back().set_name;
}
/// Consumes an element in the current scope.
void consume_element()
{
assert(!scope_stack.empty() && "Consuming element in void scope");
assert(scope_stack.back().size && "No more elements to consume");
--scope_stack.back().size;
}
/// Returns true if the current element needs a comma.
bool needs_comma() const
{
assert(!scope_stack.empty() && "No scope exists");
return scope_stack.back().size;
}
/// Returns the number of indentations required for the input nesting level.
unsigned get_indents(unsigned level) const { return level * 2; }
private:
/// Keeps track of some state required for formatting.
struct scope {
scope(unsigned size, std::string set_name) :
size(size), set_name(std::move(set_name))
{}
/// Number of elements this scope holds.
unsigned size;
/// Set name in this scope.
std::string set_name;
};
private: private:
/// Flags that the formatting should take place into a single line. /// Flags that the formatting should take place into a single line.
bool do_one_line_ctx_format = false; bool do_one_line_ctx_format = false;
std::vector<scope> scope_stack;
}; };
} // namespace srslog } // namespace srslog

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

Loading…
Cancel
Save