Merge branch 'next' into agpl_next

master
Codebot 3 years ago committed by Your Name
commit d1d38d1826

@ -22,8 +22,8 @@
#ifndef SRSRAN_DYN_BITSET_H
#define SRSRAN_DYN_BITSET_H
#include "srsran/common/srsran_assert.h"
#include "srsran/srslog/bundled/fmt/format.h"
#include "srsran/support/srsran_assert.h"
#include <cstdint>
#include <inttypes.h>
#include <string>

@ -23,7 +23,7 @@
#define SRSRAN_BOUNDED_VECTOR_H
#include "srsran/adt/detail/type_storage.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
#include <iterator>
#include <memory>
#include <type_traits>

@ -25,7 +25,7 @@
#include "srsran/adt/detail/type_storage.h"
#include "srsran/adt/expected.h"
#include "srsran/adt/pool/pool_utils.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
#include <array>
#include <cassert>

@ -24,7 +24,7 @@
#include "detail/type_storage.h"
#include "expected.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
#include <array>
namespace srsran {

@ -22,7 +22,7 @@
#ifndef SRSRAN_EXPECTED_H
#define SRSRAN_EXPECTED_H
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
#include <memory>
#include <system_error>

@ -22,8 +22,8 @@
#ifndef SRSRAN_INTERVAL_H
#define SRSRAN_INTERVAL_H
#include "srsran/common/srsran_assert.h"
#include "srsran/srslog/bundled/fmt/format.h"
#include "srsran/support/srsran_assert.h"
#include <cassert>
#include <string>
#include <type_traits>

@ -23,7 +23,7 @@
#define SRSRAN_MOVE_CALLBACK_H
#include "detail/type_storage.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
#include <cstddef>
#include <cstdint>
#include <cstdio>
@ -69,7 +69,7 @@ public:
constexpr empty_table_t() = default;
R call(void* src, Args... args) const final
{
srsran_terminate("ERROR: bad function call (cause: function ptr is empty)");
srsran_assertion_failure("bad function call (cause: function ptr is empty)");
}
void move(void* src, void* dest) const final {}
void dtor(void* src) const final {}

@ -23,7 +23,7 @@
#define SRSRAN_OPTIONAL_H
#include "detail/type_storage.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
namespace srsran {
@ -31,6 +31,8 @@ template <typename T>
class optional
{
public:
using value_type = T;
optional() : has_val_(false) {}
optional(const T& t) : has_val_(true) { storage.emplace(t); }
optional(T&& t) : has_val_(true) { storage.emplace(std::move(t)); }

@ -0,0 +1,396 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_OPTIONAL_ARRAY_H
#define SRSRAN_OPTIONAL_ARRAY_H
#include "optional.h"
#include "span.h"
#include "srsran/support/srsran_assert.h"
#include <array>
namespace srsran {
namespace detail {
template <typename Vec>
class base_optional_span
{
using base_t = base_optional_span<Vec>;
using T = typename Vec::value_type::value_type;
protected:
template <typename Obj>
class iterator_impl
{
using It = iterator_impl<Obj>;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Obj;
using difference_type = std::ptrdiff_t;
using pointer = Obj*;
using reference = Obj&;
iterator_impl() = default;
iterator_impl(base_t* parent_, size_t idx_) : parent(parent_), idx(idx_)
{
if (idx < parent->vec.size() and not parent->contains(idx)) {
++(*this);
}
}
It& operator++()
{
while (++idx < parent->vec.size() and not parent->contains(idx)) {
}
return *this;
}
It& operator--()
{
while (--idx < parent->vec.size() and not parent->contains(idx)) {
}
return *this;
}
reference operator*() { return parent->operator[](idx); }
pointer operator->() { return &parent->operator[](idx); }
bool operator==(const It& other) const { return idx == other.idx and parent == other.parent; }
bool operator!=(const It& other) const { return not(*this == other); }
private:
friend base_t;
base_t* parent = nullptr;
size_t idx = std::numeric_limits<size_t>::max();
};
size_t nof_elems = 0;
Vec vec;
public:
using value_type = T;
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
// Find first position that is empty
size_t find_first_empty(size_t start_guess = 0)
{
if (nof_elems == vec.size()) {
return vec.size();
}
for (size_t i = start_guess; i < vec.size(); ++i) {
if (not vec[i].has_value()) {
return i;
}
}
return vec.size();
}
bool contains(size_t idx) const { return idx < vec.size() and vec[idx].has_value(); }
T& operator[](size_t idx) { return *vec[idx]; }
const T& operator[](size_t idx) const { return *vec[idx]; }
bool empty() const { return nof_elems == 0; }
size_t size() const { return nof_elems; }
iterator begin() { return iterator{this, 0}; }
iterator end() { return iterator{this, vec.size()}; }
const_iterator begin() const { return const_iterator{this, 0}; }
const_iterator end() const { return const_iterator{this, vec.size()}; }
void clear()
{
this->nof_elems = 0;
for (auto& e : *this) {
e.reset();
}
}
void erase(size_t idx)
{
srsran_assert(idx < this->vec.size(), "Out-of-bounds access to array: %zd>=%zd", idx, this->vec.size());
if (this->contains(idx)) {
this->nof_elems--;
this->vec[idx].reset();
}
}
void erase(iterator it) { erase(it.idx); }
template <typename U>
void insert(size_t idx, U&& u)
{
srsran_assert(idx < this->vec.size(), "Out-of-bounds access to array: %zd>=%zd", idx, this->vec.size());
this->nof_elems += this->contains(idx) ? 0 : 1;
this->vec[idx] = std::forward<U>(u);
}
};
template <typename Vec>
class base_optional_vector : public base_optional_span<Vec>
{
using base_t = base_optional_span<Vec>;
public:
using value_type = typename base_optional_span<Vec>::value_type;
using iterator = typename base_optional_span<Vec>::iterator;
using const_iterator = typename base_optional_span<Vec>::const_iterator;
base_optional_vector() = default;
base_optional_vector(const base_optional_vector&) = default;
base_optional_vector(base_optional_vector&& other) noexcept : base_t::vec(std::move(other.vec)),
base_t::nof_elems(other.nof_elems)
{
other.nof_elems = 0;
}
base_optional_vector& operator=(const base_optional_vector&) = default;
base_optional_vector& operator =(base_optional_vector&& other) noexcept
{
this->vec = std::move(other.vec);
this->nof_elems = other.nof_elems;
this->nof_elems = 0;
return *this;
}
};
} // namespace detail
/**
* Array of optional items. The iteration is in order of indexes and correctly skips non-present items
* Pointer/References/Iterators remain valid throughout the object lifetime
* NOTE: The sorted iteration and pointer validation guarantees add some overhead if the array is very fragmented
* @tparam T type of objects
* @tparam N static size of max nof items
*/
template <typename T, size_t N>
class optional_array : public detail::base_optional_vector<std::array<optional<T>, N> >
{};
/**
* Contrarily to optional_array, this class may allocate and cause pointer/reference/iterator invalidation.
* However, the indexes will remain valid.
* @tparam T
*/
template <typename T>
class optional_vector : public detail::base_optional_vector<std::vector<optional<T> > >
{
using base_t = detail::base_optional_vector<std::vector<optional<T> > >;
public:
/// May allocate and cause pointer invalidation
template <typename U>
void insert(size_t idx, U&& u)
{
if (idx >= this->vec.size()) {
this->vec.resize(idx + 1);
}
base_t::insert(idx, std::forward<U>(u));
}
};
template <typename T>
class optional_span : public detail::base_optional_span<srsran::span<optional<T> > >
{
using base_t = detail::base_optional_span<srsran::span<optional<T> > >;
public:
template <size_t N>
optional_span(const optional_array<T, N>& ar) : base_t::vec(ar)
{}
optional_span(const optional_vector<T>& ar) : base_t::vec(ar) {}
};
namespace detail {
template <typename T>
class base_split_optional_span
{
protected:
using presence_type = typename std::conditional<std::is_const<T>::value, const bool, bool>::type;
T* ptr = nullptr;
presence_type* present_ptr = nullptr;
size_t len = 0;
template <typename Obj>
class iterator_impl
{
using It = iterator_impl<Obj>;
using Parent = typename std::
conditional<std::is_const<Obj>::value, const base_split_optional_span<T>, base_split_optional_span<T> >::type;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Obj;
using difference_type = std::ptrdiff_t;
using pointer = Obj*;
using reference = Obj&;
iterator_impl() = default;
iterator_impl(Parent* parent_, size_t idx_) : parent(parent_), idx(idx_)
{
if (idx < parent->len and not parent->contains(idx)) {
++(*this);
}
}
It& operator++()
{
while (++idx < parent->len and not parent->contains(idx)) {
}
return *this;
}
It& operator--()
{
while (--idx < parent->len and not parent->contains(idx)) {
}
return *this;
}
reference operator*() { return parent->operator[](idx); }
pointer operator->() { return &parent->operator[](idx); }
bool operator==(const It& other) const { return idx == other.idx and parent == other.parent; }
bool operator!=(const It& other) const { return not(*this == other); }
size_t get_idx() const { return idx; }
private:
Parent* parent = nullptr;
size_t idx = std::numeric_limits<size_t>::max();
};
public:
using value_type = T;
using iterator = iterator_impl<T>;
using const_iterator = iterator_impl<const T>;
constexpr base_split_optional_span() = default;
template <std::size_t N>
constexpr base_split_optional_span(value_type (&arr)[N], presence_type (&present)[N]) noexcept : ptr(arr),
present_ptr(present),
len(N)
{}
constexpr base_split_optional_span(value_type* arr, presence_type* present, size_t N) :
ptr(arr), present_ptr(present), len(N)
{}
bool contains(size_t idx) const { return idx < len and present_ptr[idx]; }
bool empty() const
{
for (size_t i = 0; i < len; ++i) {
if (present_ptr[i]) {
return false;
}
}
return true;
}
size_t size() const
{
size_t c = 0;
for (size_t i = 0; i < len; ++i) {
c += present_ptr[i] ? 1 : 0;
}
return c;
}
size_t capacity() const { return len; }
const T& operator[](size_t idx) const { return ptr[idx]; }
T& operator[](size_t idx) { return ptr[idx]; }
const T& at(size_t idx) const
{
srsran_assert(contains(idx), "Access to inexistent element of index=%zd", idx);
return ptr[idx];
}
T& at(size_t idx)
{
srsran_assert(this->contains(idx), "Access to inexistent element of index=%zd", idx);
return this->ptr[idx];
}
const_iterator begin() const { return const_iterator(this, 0); }
const_iterator end() const { return const_iterator(this, len); }
iterator begin() { return iterator(this, 0); }
iterator end() { return iterator(this, this->len); }
// Find first position that is empty
size_t find_first_empty(size_t start_guess = 0) { return begin().get_idx(); }
};
} // namespace detail
template <typename T>
class split_optional_span : public detail::base_split_optional_span<T>
{
using base_t = detail::base_split_optional_span<T>;
public:
using value_type = T;
using const_iterator = typename base_t::const_iterator;
using iterator = typename base_t::iterator;
using base_t::base_t;
template <typename U>
void insert(size_t idx, U&& u)
{
srsran_assert(idx < this->len, "Out-of-bounds access to array: %zd>=%zd", idx, this->len);
this->present_ptr[idx] = true;
this->ptr[idx] = std::forward<U>(u);
}
void erase(size_t idx)
{
srsran_assert(idx < this->len, "Out-of-bounds access to array: %zd>=%zd", idx, this->len);
this->present_ptr[idx] = false;
}
void erase(iterator it) { erase(it.get_idx()); }
void clear()
{
for (size_t i = 0; i < this->len; ++i) {
this->present_ptr[i] = false;
}
}
};
template <typename U>
class split_optional_span<const U> : public detail::base_split_optional_span<const U>
{
using base_t = detail::base_split_optional_span<const U>;
using presence_type = typename base_t::presence_type;
public:
using value_type = const U;
using const_iterator = typename base_t::const_iterator;
using base_t::base_t;
};
template <typename T>
split_optional_span<T>
make_optional_span(T* array,
typename std::conditional<std::is_const<T>::value, const bool, bool>::type* present,
size_t N)
{
return split_optional_span<T>(array, present, N);
}
template <typename T, size_t N>
split_optional_span<T>
make_optional_span(T (&array)[N],
typename std::conditional<std::is_const<T>::value, const bool, bool>::type (&present)[N])
{
return split_optional_span<T>(array, present);
}
} // namespace srsran
#endif // SRSRAN_OPTIONAL_ARRAY_H

@ -24,8 +24,8 @@
#include "memblock_cache.h"
#include "pool_utils.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/thread_pool.h"
#include "srsran/support/srsran_assert.h"
#include <memory>
#include <mutex>

@ -23,7 +23,7 @@
#define SRSRAN_LINEAR_ALLOCATOR_H
#include "pool_utils.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
namespace srsran {

@ -22,8 +22,8 @@
#ifndef SRSASN_COMMON_UTILS_H
#define SRSASN_COMMON_UTILS_H
#include "srsran/common/srsran_assert.h"
#include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_assert.h"
#include <algorithm>
#include <array>
#include <cmath>

@ -23,7 +23,7 @@
#define SRSRAN_SLOT_POINT_H
#include "srsran/adt/interval.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
namespace srsran {

@ -23,12 +23,12 @@
#define SRSRAN_TEST_COMMON_H
#include "srsran/config.h"
#include "srsran/support/srsran_test.h"
#ifdef __cplusplus
#include "srsran/common/buffer_pool.h"
#include "srsran/common/crash_handler.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h"
#include "srsran/srslog/srslog.h"
#include <atomic>
@ -168,20 +168,6 @@ inline void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg)
#define TESTERROR(fmt, ...) CONDERROR(true, fmt, ##__VA_ARGS__)
#define TESTASSERT(cond) srsran_assert((cond), "Fail at \"%s\"", (#cond))
#else // if C
#include <stdio.h>
#define TESTASSERT(cond) \
do { \
if (!(cond)) { \
printf("[%s][Line %d] Fail at \"%s\"\n", __FUNCTION__, __LINE__, (#cond)); \
return -1; \
} \
} while (0)
#endif // __cplusplus
#endif // SRSRAN_TEST_COMMON_H

@ -24,8 +24,8 @@
#include "srsran/adt/interval.h"
#include "srsran/common/common.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_assert.h"
#include <cstdint>
#include <limits>

@ -165,6 +165,15 @@ public:
// TODO: Support the following configurations
// bool do_rohc;
bool operator==(const pdcp_config_t& other) const
{
return bearer_id == other.bearer_id and rb_type == other.rb_type and tx_direction == other.tx_direction and
rx_direction == other.rx_direction and sn_len == other.sn_len and hdr_len_bytes == other.hdr_len_bytes and
t_reordering == other.t_reordering and discard_timer == other.discard_timer and rat == other.rat and
status_report_required == other.status_report_required;
}
bool operator!=(const pdcp_config_t& other) const { return not(*this == other); }
};
// Specifies in which direction security (integrity and ciphering) are enabled for PDCP

@ -286,7 +286,7 @@ SRSRAN_API int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_
/**
* @brief Packs an UL NR DCI into a DCI message
* @param q NR DCI object with precomputed DCI parameters
* @param q NR DCI object with precomputed DCI parameters (not required for RAR type, set to NULL)
* @param dci UL NR DCI to pack (serialize)
* @param[out] msg resultant DCI message
* @return SRSRAN_SUCCESS if provided arguments are valid, SRSRAN_ERROR code otherwise
@ -295,7 +295,7 @@ SRSRAN_API int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_
/**
* @brief Unpacks an NR DCI message into an UL NR DCI
* @param q NR DCI object with precomputed DCI parameters
* @param q NR DCI object with precomputed DCI parameters (not required for RAR type, set to NULL)
* @param msg DCI message to unpack (deserialize)
* @param[out] dci Resultant unpacked UL DCI
* @return SRSRAN_SUCCESS if provided arguments are valid, SRSRAN_ERROR code otherwise
@ -309,7 +309,7 @@ SRSRAN_API int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_
* @param str_len Destination string length
* @return The number of written characters
*/
SRSRAN_API int srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_len);
SRSRAN_API uint32_t srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_len);
/**
* @brief Stringifies a DL NR DCI structure
@ -319,8 +319,10 @@ SRSRAN_API int srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uin
* @param str_len Destination string length
* @return The number of written characters
*/
SRSRAN_API int
srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
SRSRAN_API uint32_t srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q,
const srsran_dci_dl_nr_t* dci,
char* str,
uint32_t str_len);
/**
* @brief Stringifies an UL NR DCI structure
@ -330,7 +332,9 @@ srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci,
* @param str_len Destination string length
* @return The number of written characters
*/
SRSRAN_API int
srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len);
SRSRAN_API uint32_t srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q,
const srsran_dci_ul_nr_t* dci,
char* str,
uint32_t str_len);
#endif // SRSRAN_DCI_NR_H

@ -53,6 +53,7 @@ typedef struct {
/**
* @brief Uplink Control Information bits configuration for PUSCH transmission
* @attention Set nof_layers, nof_re or R to 0 to indicate this structure is not initialised.
*/
typedef struct {
uint32_t l0; ///< First OFDM symbol that does not carry DMRS of the PUSCH, after the first DMRS symbol(s)
@ -62,12 +63,12 @@ typedef struct {
uint32_t K_sum; ///< Sum of UL-SCH code block sizes, set to zero if no UL-SCH
srsran_mod_t modulation; ///< Modulation for the PUSCH
uint32_t nof_layers; ///< Number of layers for PUSCH
uint32_t nof_re; ///< Total number of resource elements allocated for the grant
float R; ///< Code rate of the PUSCH
float alpha; ///< Higher layer parameter scaling
float beta_harq_ack_offset;
float beta_csi1_offset;
float beta_csi2_offset;
uint32_t nof_re;
bool csi_part2_present;
} srsran_uci_nr_pusch_cfg_t;

@ -28,12 +28,12 @@
#include "srsran/adt/intrusive_list.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/task_scheduler.h"
#include "srsran/common/timeout.h"
#include "srsran/interfaces/pdcp_interface_types.h"
#include "srsran/rlc/rlc_am_base.h"
#include "srsran/rlc/rlc_common.h"
#include "srsran/support/srsran_assert.h"
#include "srsran/upper/byte_buffer_queue.h"
#include <deque>
#include <list>

@ -22,38 +22,54 @@
#ifndef SRSRAN_ASSERT_H
#define SRSRAN_ASSERT_H
#ifdef __cplusplus
#include "srsran/srslog/srslog.h"
#include <cstdio>
#include <stdarg.h>
#define srsran_unlikely(expr) __builtin_expect(!!(expr), 0)
#define srsran_terminate(fmt, ...) \
srslog::flush(); \
std::fprintf(stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
std::abort()
#ifdef ASSERTS_ENABLED
/**
* Command to terminate srsRAN application with an error message, ensuring first that the log is flushed
*/
[[gnu::noinline, noreturn]] inline bool srsran_terminate(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
srslog::flush();
vfprintf(stderr, fmt, args);
va_end(args);
std::abort();
}
#define srsran_assertion_failure(fmt, ...) \
srsran_terminate("%s:%d: Assertion Failure: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
/**
* Macro that asserts condition is true. If false, it logs the remaining parameters, prints the backtrace and closes
* the application
* Macro that asserts condition is true. If false, it logs the remaining macro args, flushes the log,
* prints the backtrace (if it was activated) and closes the application.
*/
#define srsran_assert(condition, fmt, ...) \
do { \
if (srsran_unlikely(not(condition))) { \
srsran_terminate(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define srsran_always_assert(condition, fmt, ...) (void)((condition) || srsran_assertion_failure(fmt, ##__VA_ARGS__))
#ifdef STOP_ON_WARNING
#define SRSRAN_IS_DEFINED(x) SRSRAN_IS_DEFINED2(x)
#define SRSRAN_IS_DEFINED2(x) (#x[0] == 0 || (#x[0] >= '1' && #x[0] <= '9'))
/**
* Macro that verifies if condition is true. If false, and STOP_ON_WARNING is true, it behaves like srsran_assert.
* If STOP_ON_WARNING is false, it logs a warning.
* Same as "srsran_always_assert" but it is only active when "enable_check" flag is defined
*/
#define srsran_assert_ifdef(enable_check, condition, fmt, ...) \
(void)((not SRSRAN_IS_DEFINED(enable_check)) || (srsran_always_assert(condition, fmt, ##__VA_ARGS__), 0))
/**
* Specialization of "srsran_assert_ifdef" for the ASSERTS_ENABLED flag
*/
#define srsran_assert(condition, fmt, ...) srsran_assert_ifdef(ASSERTS_ENABLED, condition, fmt, ##__VA_ARGS__)
#ifdef STOP_ON_WARNING
#define srsran_expect(condition, fmt, ...) srsran_assert(condition, fmt, ##__VA_ARGS__)
#else // STOP_ON_WARNING
#else
#define srsran_expect(condition, fmt, ...) \
do { \
@ -62,16 +78,20 @@
} \
} while (0)
#endif // STOP_ON_WARNING
#endif
#else // __ifcplusplus
#else // ASSERTS_ENABLED
#include <cassert>
#ifdef ASSERTS_ENABLED
#define srsran_assert(condition, fmt, ...) (void)((condition) || (__assert(#condition, __FILE__, __FLAG__), 0))
#else
#define srsran_assert(condition, fmt, ...) \
do { \
} while (0)
#define srsran_expect(condition, fmt, ...) srsran_assert(condition, fmt, ##__VA_ARGS__)
#endif
#endif // __ifcplusplus
#endif // SRSRAN_ASSERT_H

@ -0,0 +1,64 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_SRSRAN_TEST_H
#define SRSRAN_SRSRAN_TEST_H
#ifdef __cplusplus
#include "srsran_assert.h"
namespace srsran {
namespace detail {
template <typename T, typename U>
[[gnu::noinline, noreturn]] void assert_eq_failure(const T& expected_val, const U& actual_val)
{
std::string s = fmt::format("Actual value '{}' differs from expected '{}'", actual_val, expected_val);
srsran_assertion_failure("%s", s.c_str());
}
template <typename T>
[[gnu::noinline, noreturn]] void assert_neq_failure(const T& actual_val)
{
std::string s = fmt::format("Value should not be equal to '{}'", actual_val);
srsran_assertion_failure("%s", s.c_str());
}
} // namespace detail
} // namespace srsran
#define TESTASSERT_EQ(EXPECTED, ACTUAL) \
(void)((EXPECTED == ACTUAL) || (::srsran::detail::assert_eq_failure(EXPECTED, ACTUAL), 0))
#define TESTASSERT_NEQ(EXPECTED, ACTUAL) \
(void)((EXPECTED != ACTUAL) || (::srsran::detail::assert_neq_failure(ACTUAL), 0))
#define TESTASSERT(cond) srsran_assert((cond), "Fail at \"%s\"", (#cond))
#define TESTASSERT_SUCCESS(cond) srsran_assert((cond == SRSRAN_SUCCESS), "Operation \"%s\" was not successful", (#cond))
#else // __cplusplus
#include <stdio.h>
#define TESTASSERT(cond) \
do { \
if (!(cond)) { \
printf("[%s][Line %d] Fail at \"%s\"\n", __FUNCTION__, __LINE__, (#cond)); \
return -1; \
} \
} while (0)
#endif // __cplusplus
#endif // SRSRAN_SRSRAN_TEST_H

@ -43,7 +43,7 @@ phy_cfg_nr_default_t::reference_cfg_t::reference_cfg_t(const std::string& args)
// Skip if size is invalid
if (param.size() != 2) {
srsran_terminate("Invalid reference argument '%s'", e.c_str());
srsran_assertion_failure("Invalid reference argument '%s'", e.c_str());
}
if (param.front() == "carrier") {
@ -68,7 +68,7 @@ phy_cfg_nr_default_t::reference_cfg_t::reference_cfg_t(const std::string& args)
}
srsran_assert(pdsch != R_PDSCH_COUNT, "Invalid PDSCH reference configuration '%s'", param.back().c_str());
} else {
srsran_terminate("Invalid %s reference component", param.front().c_str());
srsran_assertion_failure("Invalid %s reference component", param.front().c_str());
}
}
}
@ -148,6 +148,10 @@ void phy_cfg_nr_default_t::make_pdcch_custom_common_ss(srsran_pdcch_cfg_nr_t& pd
pdcch.search_space[1].nof_candidates[L] =
SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&pdcch.coreset[1], L));
}
pdcch.ra_search_space_present = true;
pdcch.ra_search_space = pdcch.search_space[1];
pdcch.ra_search_space.type = srsran_search_space_type_common_1;
}
void phy_cfg_nr_default_t::make_pdsch_default(srsran_sch_hl_cfg_nr_t& pdsch)
@ -221,7 +225,7 @@ void make_nzp_csi_rs_ts38101_table_5_2_1(const srsran_carrier_nr_t& carrier, srs
res3.periodicity.offset = 21;
res4.periodicity.offset = 21;
} else {
srsran_terminate("Invalid subcarrier spacing %d kHz", 15U << (uint32_t)carrier.scs);
srsran_assertion_failure("Invalid subcarrier spacing %d kHz", 15U << (uint32_t)carrier.scs);
}
res1.resource_mapping.freq_band = {0, carrier.nof_prb};
@ -379,7 +383,7 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
make_carrier_custom_20MHz(carrier);
break;
case reference_cfg_t::R_CARRIER_COUNT:
srsran_terminate("Invalid carrier reference");
srsran_assertion_failure("Invalid carrier reference");
}
switch (reference_cfg.tdd) {
@ -390,7 +394,7 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
make_tdd_fr1_15_1(tdd);
break;
case reference_cfg_t::R_TDD_COUNT:
srsran_terminate("Invalid TDD reference");
srsran_assertion_failure("Invalid TDD reference");
}
switch (reference_cfg.pdcch) {
@ -407,7 +411,7 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
make_pdsch_2_1_1_tdd(carrier, pdsch);
break;
case reference_cfg_t::R_PDSCH_COUNT:
srsran_terminate("Invalid PDSCH reference configuration");
srsran_assertion_failure("Invalid PDSCH reference configuration");
}
switch (reference_cfg.pusch) {

@ -102,8 +102,7 @@ void pdcp::write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu)
int pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg)
{
if (valid_lcid(lcid)) {
logger.error("Bearer %s already configured.", rrc->get_rb_name(lcid));
return SRSRAN_ERROR;
return pdcp_array[lcid]->configure(cfg) ? SRSRAN_SUCCESS : SRSRAN_ERROR;
}
std::unique_ptr<pdcp_entity_base> entity;

@ -60,6 +60,15 @@ pdcp_entity_lte::~pdcp_entity_lte()
bool pdcp_entity_lte::configure(const pdcp_config_t& cnfg_)
{
if (active) {
// Already configured
if (cnfg_ != cfg) {
logger.error("Bearer reconfiguration not supported. LCID=%d.", rrc->get_rb_name(lcid));
return false;
}
return true;
}
cfg = cnfg_;
maximum_pdcp_sn = (1u << cfg.sn_len) - 1u;
st.last_submitted_pdcp_rx_sn = maximum_pdcp_sn;

@ -52,6 +52,15 @@ void pdcp_entity_nr::reestablish()
bool pdcp_entity_nr::configure(const pdcp_config_t& cnfg_)
{
if (active) {
// Already configured
if (cnfg_ != cfg) {
logger.error("Bearer reconfiguration not supported. LCID=%d.", rrc->get_rb_name(lcid));
return false;
}
return true;
}
cfg = cnfg_;
window_size = 1 << (cfg.sn_len - 1);

@ -19,8 +19,8 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/srsran.h"
#include "srsran/support/srsran_test.h"
#include <complex.h>
#include <stdio.h>
#include <stdlib.h>

@ -19,8 +19,8 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/support/srsran_test.h"
static srsran_carrier_nr_t carrier = {};

@ -19,9 +19,9 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/utils/vector.h"
#include "srsran/support/srsran_test.h"
#include <getopt.h>
#include <srsran/srsran.h>
#include <stdlib.h>

@ -19,9 +19,9 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/ch_estimation/dmrs_pdcch.h"
#include "srsran/phy/phch/pdcch_nr.h"
#include "srsran/support/srsran_test.h"
#include <complex.h>
#include <stdio.h>
#include <stdlib.h>

@ -19,10 +19,10 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/ch_estimation/dmrs_sch.h"
#include "srsran/phy/phch/ra_dl_nr.h"
#include "srsran/srsran.h"
#include "srsran/support/srsran_test.h"
#include <complex.h>
#include <stdio.h>
#include <stdlib.h>

@ -18,10 +18,10 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/fec/block/block.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/random.h"
#include "srsran/support/srsran_test.h"
#include <memory.h>
#include <srsran/phy/utils/vector.h>
#include <stdio.h>

@ -20,8 +20,8 @@
*/
#include "polar_interleaver_gold.h"
#include "srsran/common/test_common.h"
#include "srsran/phy/fec/polar/polar_interleaver.h"
#include "srsran/support/srsran_test.h"
int main(int argc, char** argv)
{

@ -224,7 +224,8 @@ static int dci_nr_format_0_0_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_
msg->ctx = dci->ctx;
// Check RNTI type
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) {
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c &&
rnti_type != srsran_rnti_type_tc) {
return SRSRAN_ERROR;
}
@ -294,7 +295,8 @@ static int dci_nr_format_0_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_
uint32_t N_UL_BWP_RB = SRSRAN_SEARCH_SPACE_IS_COMMON(ss_type) ? q->cfg.bwp_ul_initial_bw : q->cfg.bwp_ul_active_bw;
// Check RNTI type
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c) {
if (rnti_type != srsran_rnti_type_c && rnti_type != srsran_rnti_type_cs && rnti_type != srsran_rnti_type_mcs_c &&
rnti_type != srsran_rnti_type_tc) {
ERROR("Unsupported %s", srsran_rnti_type_str(rnti_type));
return SRSRAN_ERROR;
}
@ -356,7 +358,7 @@ static int dci_nr_format_0_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_
return SRSRAN_SUCCESS;
}
static int dci_nr_format_0_0_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
static uint32_t dci_nr_format_0_0_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
@ -715,7 +717,7 @@ static int dci_nr_format_0_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_
return SRSRAN_SUCCESS;
}
static int
static uint32_t
dci_nr_format_0_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
@ -820,6 +822,112 @@ dci_nr_format_0_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci
return len;
}
static uint32_t dci_nr_rar_sizeof()
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint32_t count = 0;
// Frequency hopping flag - 1 bit
count += 1;
// PUSCH frequency resource allocation - 14 bits
count += 14;
// PUSCH time resource allocation - 4 bits
count += 4;
// MCS - 4 bits
count += 4;
// TPC command for PUSCH - 3 bits
count += 3;
// CSI request - 1 bits
count += 1;
return count;
}
static int dci_nr_rar_pack(const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint8_t* y = msg->payload;
// Frequency hopping flag - 1 bit
srsran_bit_unpack(dci->freq_hopping_flag, &y, 1);
// PUSCH frequency resource allocation - 14 bits
srsran_bit_unpack(dci->freq_domain_assigment, &y, 14);
// PUSCH time resource allocation - 4 bits
srsran_bit_unpack(dci->time_domain_assigment, &y, 4);
// MCS - 4 bits
srsran_bit_unpack(dci->mcs, &y, 4);
// TPC command for PUSCH - 3 bits
srsran_bit_unpack(dci->tpc, &y, 3);
// CSI request - 1 bits
srsran_bit_unpack(dci->csi_request, &y, 1);
return SRSRAN_SUCCESS;
}
static int dci_nr_rar_unpack(srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
// Fields described by TS 38.213 Table 8.2-1: Random Access Response Grant Content field size
uint8_t* y = msg->payload;
// Copy DCI MSG fields
dci->ctx = msg->ctx;
// Frequency hopping flag - 1 bit
dci->freq_hopping_flag = srsran_bit_pack(&y, 1);
// PUSCH frequency resource allocation - 14 bits
dci->freq_domain_assigment = srsran_bit_pack(&y, 14);
// PUSCH time resource allocation - 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, 4);
// MCS -4 bits
dci->mcs = srsran_bit_pack(&y, 4);
// TPC command for PUSCH - 3 bits
dci->tpc = srsran_bit_pack(&y, 3);
// CSI request - 1 bits
dci->csi_request = srsran_bit_pack(&y, 1);
return SRSRAN_SUCCESS;
}
static uint32_t dci_nr_rar_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
// Frequency hopping flag
len = srsran_print_check(str, str_len, len, "hop=%d ", dci->freq_hopping_flag);
// PUSCH frequency resource allocation
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// PUSCH time resource allocation
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// Modulation and coding scheme
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// TPC command for scheduled PUSCH
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
// CSI request
len = srsran_print_check(str, str_len, len, "csi=%d ", dci->csi_request);
return len;
}
static uint32_t dci_nr_format_1_0_sizeof(uint32_t N_DL_BWP_RB, srsran_rnti_type_t rnti_type)
{
uint32_t count = 0;
@ -1132,7 +1240,7 @@ static int dci_nr_format_1_0_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_
return SRSRAN_SUCCESS;
}
static int dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
static uint32_t dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
srsran_rnti_type_t rnti_type = dci->ctx.rnti_type;
@ -1569,7 +1677,7 @@ static int dci_nr_format_1_1_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_
return SRSRAN_SUCCESS;
}
static int
static uint32_t
dci_nr_format_1_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
@ -1684,6 +1792,10 @@ dci_nr_format_1_1_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci
int srsran_dci_nr_set_cfg(srsran_dci_nr_t* q, const srsran_dci_cfg_nr_t* cfg)
{
if (q == NULL || cfg == NULL) {
return SRSRAN_ERROR;
}
// Reset current setup
SRSRAN_MEM_ZERO(q, srsran_dci_nr_t, 1);
@ -1825,6 +1937,11 @@ uint32_t srsran_dci_nr_size(const srsran_dci_nr_t* q, srsran_search_space_type_t
return q->dci_1_1_size;
}
// RAR packed MSG3 DCI
if (format == srsran_dci_format_nr_rar) {
return dci_nr_rar_sizeof();
}
// Not implemented
return 0;
}
@ -1853,71 +1970,12 @@ bool srsran_dci_nr_valid_direction(const srsran_dci_msg_nr_t* dci)
return (dci->ctx.format == srsran_dci_format_nr_1_0);
}
static int dci_nr_rar_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
ERROR("Not implemented");
return SRSRAN_ERROR;
}
static int dci_nr_rar_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
if (msg == NULL || dci == NULL) {
if (q == NULL || dci == NULL || msg == NULL) {
return SRSRAN_ERROR;
}
uint8_t* y = msg->payload;
// Copy DCI MSG fields
dci->ctx = msg->ctx;
// Frequency hopping flag - 1 bit
dci->freq_hopping_flag = srsran_bit_pack(&y, 1);
// PUSCH frequency resource allocation - 14 bits
dci->freq_domain_assigment = srsran_bit_pack(&y, 14);
// PUSCH time resource allocation - 4 bits
dci->time_domain_assigment = srsran_bit_pack(&y, 4);
// MCS -4 bits
dci->mcs = srsran_bit_pack(&y, 4);
// TPC command for PUSCH - 3 bits
dci->tpc = srsran_bit_pack(&y, 3);
// CSI request - 1 bits
dci->csi_request = srsran_bit_pack(&y, 3);
return SRSRAN_SUCCESS;
}
static int dci_nr_rar_to_str(const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
uint32_t len = 0;
// Frequency hopping flag
len = srsran_print_check(str, str_len, len, "hop=%d ", dci->freq_hopping_flag);
// PUSCH frequency resource allocation
len = srsran_print_check(str, str_len, len, "f_alloc=0x%x ", dci->freq_domain_assigment);
// PUSCH time resource allocation
len = srsran_print_check(str, str_len, len, "t_alloc=0x%x ", dci->time_domain_assigment);
// Modulation and coding scheme
len = srsran_print_check(str, str_len, len, "mcs=%d ", dci->mcs);
// TPC command for scheduled PUSCH
len = srsran_print_check(str, str_len, len, "tpc=%d ", dci->tpc);
// CSI request
len = srsran_print_check(str, str_len, len, "csi=%d ", dci->csi_request);
return len;
}
int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
// Copy DCI MSG fields
msg->ctx = dci->ctx;
@ -1936,6 +1994,10 @@ int srsran_dci_nr_dl_pack(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dc
int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_dl_nr_t* dci)
{
if (q == NULL || dci == NULL || msg == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
dci->ctx = msg->ctx;
@ -1953,6 +2015,14 @@ int srsran_dci_nr_dl_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg,
int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, srsran_dci_msg_nr_t* msg)
{
if (msg == NULL || dci == NULL) {
return SRSRAN_ERROR;
}
if (dci->ctx.format != srsran_dci_format_nr_rar && q == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
msg->ctx = dci->ctx;
@ -1963,7 +2033,7 @@ int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dc
case srsran_dci_format_nr_0_1:
return dci_nr_format_0_1_pack(q, dci, msg);
case srsran_dci_format_nr_rar:
return dci_nr_rar_pack(q, dci, msg);
return dci_nr_rar_pack(dci, msg);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
@ -1973,6 +2043,14 @@ int srsran_dci_nr_ul_pack(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dc
int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg, srsran_dci_ul_nr_t* dci)
{
if (msg == NULL || dci == NULL) {
return SRSRAN_ERROR;
}
if (msg->ctx.format != srsran_dci_format_nr_rar && q == NULL) {
return SRSRAN_ERROR;
}
// Copy DCI MSG fields
dci->ctx = msg->ctx;
@ -1983,15 +2061,19 @@ int srsran_dci_nr_ul_unpack(const srsran_dci_nr_t* q, srsran_dci_msg_nr_t* msg,
case srsran_dci_format_nr_0_1:
return dci_nr_format_0_1_unpack(q, msg, dci);
case srsran_dci_format_nr_rar:
return dci_nr_rar_unpack(q, msg, dci);
return dci_nr_rar_unpack(msg, dci);
default:
ERROR("Unsupported DCI format %d", msg->ctx.format);
}
return SRSRAN_ERROR;
}
int srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_len)
uint32_t srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_len)
{
if (ctx == NULL || str == NULL) {
return 0;
}
uint32_t len = 0;
// Print base
@ -2010,8 +2092,12 @@ int srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t str_l
return len;
}
int srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
uint32_t srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len)
{
if (q == NULL || dci == NULL || str == NULL) {
return 0;
}
uint32_t len = 0;
len += srsran_dci_ctx_to_str(&dci->ctx, &str[len], str_len - len);
@ -2035,8 +2121,12 @@ int srsran_dci_ul_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_ul_nr_t*
return len;
}
int srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
uint32_t srsran_dci_dl_nr_to_str(const srsran_dci_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len)
{
if (q == NULL || dci == NULL || str == NULL) {
return SRSRAN_ERROR;
}
uint32_t len = 0;
len += srsran_dci_ctx_to_str(&dci->ctx, &str[len], str_len - len);

@ -19,10 +19,10 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/random.h"
#include "srsran/support/srsran_test.h"
#include <getopt.h>
static uint32_t nof_repetitions = 1024;
@ -99,6 +99,7 @@ static int test_52prb_base()
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_0) == 39);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_1) == 36);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_1) == 41);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_rar, srsran_dci_format_nr_rar) == 27);
srsran_dci_ctx_t ctx = {};
ctx.rnti = 0x1234;
@ -202,6 +203,55 @@ static int test_52prb_base()
TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_ul_nr_t)) == 0);
}
// Test UL DCI RAR Packing/Unpacking and info
ctx.ss_type = srsran_search_space_type_rar;
ctx.format = srsran_dci_format_nr_rar;
for (uint32_t i = 0; i < nof_repetitions; i++) {
srsran_dci_ul_nr_t dci_tx = {};
dci_tx.ctx = ctx;
dci_tx.freq_domain_assigment = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 14U) - 1); // 14 bit
dci_tx.time_domain_assigment = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 4U) - 1); // 4 bit
dci_tx.freq_hopping_flag = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 1U) - 1); // 1 bit
dci_tx.mcs = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 4U) - 1); // 4 bit
dci_tx.rv = 0; // unavailable
dci_tx.ndi = 0; // unavailable
dci_tx.pid = 0; // unavailable
dci_tx.tpc = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 3U) - 1); // 3 bit
dci_tx.frequency_offset = 0; // unavailable
dci_tx.csi_request = srsran_random_uniform_int_dist(random_gen, 0, (int)(1U << 1U) - 1); // 1 bit
dci_tx.sul = 0; // unavailable
dci_tx.cc_id = 0; // unavailable
dci_tx.bwp_id = 0; // unavailable
dci_tx.dai1 = 0; // unavailable
dci_tx.dai2 = 0; // unavailable
dci_tx.srs_id = 0; // unavailable
dci_tx.ports = 0; // unavailabale
dci_tx.srs_request = 0; // unavailabale
dci_tx.cbg_info = 0; // unavailable
dci_tx.ptrs_id = 0; // unavailable
dci_tx.beta_id = 0; // unavailable
dci_tx.dmrs_id = 0; // unavailabale
dci_tx.ulsch = 0; // unavailabale
// Pack
srsran_dci_msg_nr_t dci_msg = {};
TESTASSERT(srsran_dci_nr_ul_pack(&dci, &dci_tx, &dci_msg) == SRSRAN_SUCCESS);
// Unpack
srsran_dci_ul_nr_t dci_rx = {};
TESTASSERT(srsran_dci_nr_ul_unpack(&dci, &dci_msg, &dci_rx) == SRSRAN_SUCCESS);
// To string
char str[512];
TESTASSERT(srsran_dci_ul_nr_to_str(&dci, &dci_tx, str, (uint32_t)sizeof(str)) != 0);
INFO("Tx: %s", str);
TESTASSERT(srsran_dci_ul_nr_to_str(&dci, &dci_rx, str, (uint32_t)sizeof(str)) != 0);
INFO("Rx: %s", str);
// Assert
TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_ul_nr_t)) == 0);
}
// Test UL DCI 1_0 Packing/Unpacking and info
ctx.format = srsran_dci_format_nr_1_0;
for (uint32_t i = 0; i < nof_repetitions; i++) {
@ -255,7 +305,7 @@ static int test_52prb_base()
TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_dl_nr_t)) == 0);
}
// Test UL DCI 1_0 Packing/Unpacking and info
// Test UL DCI 1_1 Packing/Unpacking and info
ctx.format = srsran_dci_format_nr_1_1;
for (uint32_t i = 0; i < nof_repetitions; i++) {
srsran_dci_dl_nr_t dci_tx = {};

@ -42,6 +42,40 @@ uint32_t srsran_uci_nr_crc_len(uint32_t A)
return (A <= 11) ? 0 : (A < 20) ? 6 : 11;
}
static inline int uci_nr_pusch_cfg_valid(const srsran_uci_nr_pusch_cfg_t* cfg)
{
// No data pointer
if (cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Unset configuration is unset
if (cfg->nof_re == 0 && cfg->nof_layers == 0 && !isnormal(cfg->R)) {
return SRSRAN_SUCCESS;
}
// Detect invalid number of layers
if (cfg->nof_layers == 0) {
ERROR("Invalid number of layers %d", cfg->nof_layers);
return SRSRAN_ERROR;
}
// Detect invalid number of RE
if (cfg->nof_re == 0) {
ERROR("Invalid number of RE %d", cfg->nof_re);
return SRSRAN_ERROR;
}
// Detect invalid Rate
if (!isnormal(cfg->R)) {
ERROR("Invalid R %f", cfg->R);
return SRSRAN_ERROR;
}
// Otherwise it is set and valid
return 1;
}
int srsran_uci_nr_init(srsran_uci_nr_t* q, const srsran_uci_nr_args_t* args)
{
if (q == NULL || args == NULL) {
@ -1024,10 +1058,6 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin
static int uci_nr_pusch_Q_prime_ack(const srsran_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack)
{
if (cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
uint32_t L_ack = srsran_uci_nr_crc_len(O_ack); // Number of CRC bits
uint32_t Qm = srsran_mod_bits_x_symbol(cfg->modulation); // modulation order of the PUSCH
@ -1055,14 +1085,15 @@ static int uci_nr_pusch_Q_prime_ack(const srsran_uci_nr_pusch_cfg_t* cfg, uint32
int srsran_uci_nr_pusch_ack_nof_bits(const srsran_uci_nr_pusch_cfg_t* cfg, uint32_t O_ack)
{
// Check inputs
if (cfg == NULL) {
// Validate configuration
int err = uci_nr_pusch_cfg_valid(cfg);
if (err < SRSRAN_SUCCESS) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (cfg->nof_layers == 0) {
ERROR("Invalid number of layers (%d)", cfg->nof_layers);
return SRSRAN_ERROR;
// Configuration is unset
if (err == 0) {
return 0;
}
int Q_ack_prime = uci_nr_pusch_Q_prime_ack(cfg, O_ack);
@ -1186,11 +1217,17 @@ static int uci_nr_pusch_Q_prime_csi1(const srsran_uci_nr_pusch_cfg_t* cfg, uint3
int srsran_uci_nr_pusch_csi1_nof_bits(const srsran_uci_cfg_nr_t* cfg)
{
// Check inputs
if (cfg == NULL) {
// Validate configuration
int err = uci_nr_pusch_cfg_valid(&cfg->pusch);
if (err < SRSRAN_SUCCESS) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Configuration is unset
if (err == 0) {
return 0;
}
int O_csi1 = srsran_csi_part1_nof_bits(cfg->csi, cfg->nof_csi);
if (O_csi1 < SRSRAN_SUCCESS) {
ERROR("Errpr calculating CSI part 1 number of bits");

@ -19,8 +19,8 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/phy/utils/re_pattern.h"
#include "srsran/support/srsran_test.h"
int main(int argc, char** argv)
{

@ -19,7 +19,7 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/support/srsran_test.h"
#include <complex.h>
#include <math.h>
#include <pthread.h>

@ -73,3 +73,7 @@ add_test(optional_test optional_test)
add_executable(cached_alloc_test cached_alloc_test.cc)
target_link_libraries(cached_alloc_test srsran_common)
add_test(cached_alloc_test cached_alloc_test)
add_executable(optional_array_test optional_array_test.cc)
target_link_libraries(optional_array_test srsran_common)
add_test(optional_array_test optional_array_test)

@ -20,7 +20,7 @@
*/
#include "srsran/adt/bounded_vector.h"
#include "srsran/common/test_common.h"
#include "srsran/support/srsran_test.h"
namespace srsran {
@ -61,7 +61,7 @@ struct moveonly {
moveonly& operator=(moveonly&&) noexcept = default;
};
int test_ctor()
void test_ctor()
{
// TEST: default ctor
bounded_vector<int, 10> a;
@ -97,11 +97,9 @@ int test_ctor()
bounded_vector<int, 20> a6(std::move(a5));
TESTASSERT(a6.size() == 7);
TESTASSERT(a5.size() == 0);
return SRSRAN_SUCCESS;
}
int test_obj_add_rem()
void test_obj_add_rem()
{
// TEST: push_back / emplace_back
bounded_vector<C, 10> a;
@ -163,11 +161,9 @@ int test_obj_add_rem()
a2.clear();
a = std::move(a2);
TESTASSERT(a.empty() and a2.empty());
return SRSRAN_SUCCESS;
}
int test_move_only_type()
void test_move_only_type()
{
bounded_vector<moveonly, 10> a(5);
TESTASSERT(a.size() == 5);
@ -184,24 +180,21 @@ int test_move_only_type()
a2.push_back(moveonly());
TESTASSERT(a2.size() == 7);
return SRSRAN_SUCCESS;
}
int assert_dtor_consistency()
void assert_dtor_consistency()
{
TESTASSERT(C::nof_dtor == C::nof_copy_ctor + C::nof_value_ctor + C::nof_move_ctor);
return SRSRAN_SUCCESS;
}
} // namespace srsran
int main()
{
TESTASSERT(srsran::test_ctor() == SRSRAN_SUCCESS);
TESTASSERT(srsran::test_obj_add_rem() == SRSRAN_SUCCESS);
TESTASSERT(srsran::test_move_only_type() == SRSRAN_SUCCESS);
TESTASSERT(srsran::assert_dtor_consistency() == SRSRAN_SUCCESS);
srsran::test_ctor();
srsran::test_obj_add_rem();
srsran::test_move_only_type();
srsran::assert_dtor_consistency();
printf("Success\n");
return 0;
}

@ -0,0 +1,123 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/adt/optional_array.h"
#include "srsran/common/test_common.h"
namespace srsran {
void test_optional_array()
{
optional_array<int, 5> table1;
TESTASSERT(table1.size() == 0 and table1.empty());
TESTASSERT(not table1.contains(0));
table1.insert(0, 5);
TESTASSERT(table1.size() == 1 and not table1.empty());
table1.erase(0);
TESTASSERT(table1.size() == 0 and table1.empty());
table1.insert(1, 3);
table1.insert(4, 2);
TESTASSERT(table1.size() == 2);
TESTASSERT(table1[4] == 2 and table1[1] == 3);
size_t count = 0;
int array[] = {3, 2};
for (int e : table1) {
TESTASSERT(array[count++] == e);
}
auto it = table1.begin();
TESTASSERT(*it == 3);
table1.erase(it);
TESTASSERT(table1.size() == 1);
}
void test_optional_vector()
{
optional_vector<int> table1;
TESTASSERT(table1.size() == 0 and table1.empty());
TESTASSERT(not table1.contains(0));
table1.insert(0, 5);
TESTASSERT(table1.size() == 1 and not table1.empty());
table1.erase(0);
TESTASSERT(table1.size() == 0 and table1.empty());
table1.insert(1, 3);
table1.insert(4, 2);
TESTASSERT(table1.size() == 2);
TESTASSERT(table1[4] == 2 and table1[1] == 3);
size_t count = 0;
int array[] = {3, 2};
for (int e : table1) {
TESTASSERT(array[count++] == e);
}
auto it = table1.begin();
TESTASSERT(*it == 3);
table1.erase(it);
TESTASSERT(table1.size() == 1);
}
void test_split_optional_span()
{
constexpr size_t L = 7;
int some_list[L] = {};
bool some_list_presence[L] = {};
split_optional_span<int> view(some_list, some_list_presence, L);
TESTASSERT(view.size() == 0 and view.empty());
TESTASSERT(view.begin() == view.end());
TESTASSERT(not view.contains(0));
TESTASSERT(view.find_first_empty() == L);
view.insert(1, 1);
TESTASSERT(view.size() == 1 and not view.empty());
TESTASSERT(view.begin() != view.end() and *view.begin() == 1);
TESTASSERT(view.contains(1));
TESTASSERT(view[1] == 1);
TESTASSERT(view.find_first_empty() == 1);
view.insert(3, 3);
TESTASSERT(view[3] == 3);
size_t c = 0;
for (auto& e : view) {
TESTASSERT(c == 0 ? e == 1 : e == 3);
c++;
}
TESTASSERT(view.size() == 2);
view.erase(view.begin());
TESTASSERT(view.size() == 1);
TESTASSERT(not view.contains(1) and view.contains(3));
view.clear();
TESTASSERT(view.empty());
}
} // namespace srsran
int main(int argc, char** argv)
{
auto& test_log = srslog::fetch_basic_logger("TEST");
test_log.set_level(srslog::basic_levels::info);
srsran::test_init(argc, argv);
srsran::test_optional_array();
srsran::test_optional_vector();
srsran::test_split_optional_span();
printf("Success\n");
return SRSRAN_SUCCESS;
}

@ -19,8 +19,8 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/common/timers.h"
#include "srsran/support/srsran_test.h"
#include <iostream>
#include <random>
#include <srsran/common/tti_sync_cv.h>
@ -30,7 +30,7 @@ using namespace srsran;
static_assert(timer_handler::max_timer_duration() == 1073741823, "Invalid max duration");
int timers_test1()
void timers_test1()
{
timer_handler timers;
uint32_t dur = 5;
@ -119,8 +119,6 @@ int timers_test1()
}
// TEST: timer dtor is called and removes "timer" from "timers"
TESTASSERT(timers.nof_timers() == 0);
return SRSRAN_SUCCESS;
}
/**
@ -128,7 +126,7 @@ int timers_test1()
* - calling stop() early, forbids the timer from getting expired
* - calling stop() after timer has expired should be a noop
*/
int timers_test2()
void timers_test2()
{
timer_handler timers;
uint32_t duration = 2;
@ -154,15 +152,13 @@ int timers_test2()
// TEST 2: call utimer.stop() after it expires and assert it is still expired
utimer2.stop();
TESTASSERT(utimer2.is_expired());
return SRSRAN_SUCCESS;
}
/**
* Description:
* - setting a new duration while the timer is already running should not stop timer, and should extend timeout
*/
int timers_test3()
void timers_test3()
{
timer_handler timers;
uint32_t duration = 5;
@ -185,8 +181,6 @@ int timers_test3()
}
timers.step_all();
TESTASSERT(not utimer.is_running() and utimer.is_expired());
return SRSRAN_SUCCESS;
}
struct timers_test4_ctxt {
@ -227,7 +221,7 @@ static void timers2_test4_thread(timers_test4_ctxt* ctx)
}
}
int timers_test4()
void timers_test4()
{
timer_handler timers;
timers_test4_ctxt ctx;
@ -304,14 +298,12 @@ int timers_test4()
for (uint32_t i = 0; i < nof_timers; i++) {
TESTASSERT(not ctx.timers[i].is_running());
}
return SRSRAN_SUCCESS;
}
/**
* Description: Delaying a callback using the timer_handler
*/
int timers_test5()
void timers_test5()
{
timer_handler timers;
TESTASSERT(timers.nof_timers() == 0);
@ -363,14 +355,12 @@ int timers_test5()
TESTASSERT(timers.nof_timers() == 1);
TESTASSERT(vals.size() == 3);
TESTASSERT(vals[2] == 3);
return SRSRAN_SUCCESS;
}
/**
* Description: Check if erasure of a running timer is safe
*/
int timers_test6()
void timers_test6()
{
timer_handler timers;
@ -408,8 +398,6 @@ int timers_test6()
// TEST: The second timer's callback should be the one being called, and should be called only once
timers.step_all();
TESTASSERT(vals.size() == 1 and vals[0] == 3);
return SRSRAN_SUCCESS;
}
/**
@ -417,7 +405,7 @@ int timers_test6()
* - check if timer update is safe when its new updated wheel position matches the previous wheel position
* - multime timers can exist in the same wheel position
*/
int timers_test7()
void timers_test7()
{
timer_handler timers;
size_t wheel_size = timer_handler::get_wheel_size();
@ -458,19 +446,17 @@ int timers_test7()
TESTASSERT(not t2.is_expired() and t2.is_running());
TESTASSERT(t3.is_expired() and not t3.is_running());
TESTASSERT(timers.nof_running_timers() == 1 and timers.nof_timers() == 3);
return SRSRAN_SUCCESS;
}
int main()
{
TESTASSERT(timers_test1() == SRSRAN_SUCCESS);
TESTASSERT(timers_test2() == SRSRAN_SUCCESS);
TESTASSERT(timers_test3() == SRSRAN_SUCCESS);
TESTASSERT(timers_test4() == SRSRAN_SUCCESS);
TESTASSERT(timers_test5() == SRSRAN_SUCCESS);
TESTASSERT(timers_test6() == SRSRAN_SUCCESS);
TESTASSERT(timers_test7() == SRSRAN_SUCCESS);
timers_test1();
timers_test2();
timers_test3();
timers_test4();
timers_test5();
timers_test6();
timers_test7();
printf("Success\n");
return 0;
}

@ -20,12 +20,12 @@
*/
#include "srsran/common/slot_point.h"
#include "srsran/common/test_common.h"
#include "srsran/common/tti_point.h"
#include "srsran/support/srsran_test.h"
using srsran::tti_point;
int test_tti_type()
void test_tti_type()
{
// TEST: constructors
tti_point tti1;
@ -72,8 +72,6 @@ int test_tti_type()
TESTASSERT(tti_point{1u - 2u} == tti_point{10239});
TESTASSERT(tti_point{1u - 100u} == tti_point{10141});
TESTASSERT(tti_point{10239u + 3u} == tti_point{2});
return SRSRAN_SUCCESS;
}
void test_nr_slot_type()

@ -30,6 +30,30 @@
namespace srsenb {
namespace sched_nr_impl {
/// SIB scheduler
class si_sched
{
public:
explicit si_sched(const bwp_params& bwp_cfg_);
void run_slot(bwp_slot_allocator& slot_alloc);
private:
const bwp_params* bwp_cfg = nullptr;
srslog::basic_logger& logger;
struct sched_si_t {
uint32_t n = 0;
uint32_t len = 0;
uint32_t win_len = 0;
uint32_t period = 0;
uint32_t n_tx = 0;
alloc_result result = alloc_result::invalid_coderate;
slot_point win_start;
};
srsran::bounded_vector<sched_si_t, 10> pending_sis;
};
using dl_sched_rar_info_t = sched_nr_interface::dl_sched_rar_info_t;
/// RAR/Msg3 scheduler
@ -38,9 +62,9 @@ class ra_sched
public:
explicit ra_sched(const bwp_params& bwp_cfg_);
int dl_rach_info(const dl_sched_rar_info_t& rar_info);
void run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues);
size_t empty() const { return pending_rars.empty(); }
int dl_rach_info(const dl_sched_rar_info_t& rar_info);
void run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues);
bool empty() const { return pending_rars.empty(); }
private:
struct pending_rar_t {

@ -65,6 +65,12 @@ struct bwp_params {
uint32_t P;
uint32_t N_rbg;
struct slot_cfg {
bool is_dl;
bool is_ul;
};
srsran::bounded_vector<slot_cfg, SRSRAN_NOF_SF_X_FRAME> slots;
struct pusch_ra_time_cfg {
uint32_t msg3_delay; ///< Includes K2 and delta. See TS 36.214 6.1.2.1.1-2/4/5
uint32_t K;

@ -52,7 +52,6 @@ struct bwp_slot_grid {
uint32_t slot_idx;
const bwp_params* cfg;
bool is_dl, is_ul;
bwp_rb_bitmap dl_prbs;
bwp_rb_bitmap ul_prbs;
pdcch_dl_list_t dl_pdcchs;
@ -65,6 +64,9 @@ struct bwp_slot_grid {
bwp_slot_grid() = default;
explicit bwp_slot_grid(const bwp_params& bwp_params, uint32_t slot_idx_);
void reset();
bool is_dl() const { return cfg->slots[slot_idx].is_dl; }
bool is_ul() const { return cfg->slots[slot_idx].is_ul; }
};
struct bwp_res_grid {
@ -92,6 +94,7 @@ public:
void new_slot(slot_point pdcch_slot_) { pdcch_slot = pdcch_slot_; }
alloc_result alloc_si(uint32_t aggr_idx, uint32_t si_idx, uint32_t si_ntx, const prb_interval& prbs);
alloc_result alloc_rar_and_msg3(uint16_t ra_rnti,
uint32_t aggr_idx,
prb_interval interv,

@ -64,11 +64,13 @@ public:
srsran_sch_hl_cfg_nr_t pdsch = {};
srsran_sch_hl_cfg_nr_t pusch = {};
uint32_t rar_window_size = 8;
uint32_t numerology_idx = 0;
};
struct cell_cfg_t {
srsran_carrier_nr_t carrier = {};
srsran_tdd_config_nr_t tdd = {};
srsran::phy_cfg_nr_t::ssb_cfg_t ssb = {};
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common
};

@ -24,7 +24,7 @@
#include "srsran/adt/bounded_bitset.h"
#include "srsran/adt/interval.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/support/srsran_assert.h"
extern "C" {
#include "srsran/phy/phch/ra.h"
}
@ -55,7 +55,7 @@ inline uint32_t cell_nof_prb_to_rbg(uint32_t nof_prbs)
case 100:
return 25;
default:
srsran_terminate("Provided nof PRBs not valid");
srsran_assertion_failure("Provided nof PRBs not valid");
}
return 0;
}
@ -77,7 +77,7 @@ inline uint32_t cell_nof_rbg_to_prb(uint32_t nof_rbgs)
case 25:
return 100;
default:
srsran_terminate("Provided nof PRBs not valid");
srsran_assertion_failure("Provided nof PRBs not valid");
}
return 0;
}

@ -26,6 +26,64 @@
namespace srsenb {
namespace sched_nr_impl {
si_sched::si_sched(const bwp_params& bwp_cfg_) : bwp_cfg(&bwp_cfg_), logger(srslog::fetch_basic_logger("MAC")) {}
void si_sched::run_slot(bwp_slot_allocator& slot_alloc)
{
const uint32_t si_aggr_level = 2;
slot_point pdcch_slot = slot_alloc.get_pdcch_tti();
const prb_bitmap& prbs = slot_alloc.res_grid()[pdcch_slot].dl_prbs.prbs();
// Update SI windows
uint32_t N = bwp_cfg->slots.size();
for (sched_si_t& si : pending_sis) {
uint32_t x = (si.n - 1) * si.win_len;
if (not si.win_start.valid() and (pdcch_slot.sfn() % si.period == x / N) and
pdcch_slot.slot_idx() == x % bwp_cfg->slots.size()) {
// If start o SI message window
si.win_start = pdcch_slot;
} else if (si.win_start.valid() and si.win_start + si.win_len >= pdcch_slot) {
// If end of SI message window
logger.warning(
"SCHED: Could not allocate SI message idx=%d, len=%d. Cause: %s", si.n, si.len, to_string(si.result));
si.win_start.clear();
}
}
// Schedule pending SIs
if (bwp_cfg->slots[pdcch_slot.slot_idx()].is_dl) {
for (sched_si_t& si : pending_sis) {
if (not si.win_start.valid()) {
continue;
}
// TODO: NOTE 2: The UE is not required to monitor PDCCH monitoring occasion(s) corresponding to each transmitted
// SSB in SI-window.
// Attempt grants with increasing number of PRBs (if the number of PRBs is too low, the coderate is invalid)
si.result = alloc_result::invalid_coderate;
uint32_t prb_start_idx = 0;
for (uint32_t nprbs = 4; nprbs < bwp_cfg->cfg.rb_width and si.result == alloc_result::invalid_coderate; ++nprbs) {
prb_interval grant = find_empty_interval_of_length(prbs, nprbs, prb_start_idx);
prb_start_idx = grant.start();
if (grant.length() != nprbs) {
si.result = alloc_result::no_sch_space;
break;
}
si.result = slot_alloc.alloc_si(si_aggr_level, si.n, si.n_tx, grant);
if (si.result == alloc_result::success) {
// SIB scheduled successfully
si.win_start.clear();
si.n_tx++;
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ra_sched::ra_sched(const bwp_params& bwp_cfg_) : bwp_cfg(&bwp_cfg_), logger(srslog::fetch_basic_logger("MAC")) {}
alloc_result ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid,
@ -43,7 +101,7 @@ alloc_result ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid,
uint32_t start_prb_idx = 0;
for (uint32_t nprb = 4; nprb < bwp_cfg->cfg.rb_width and ret == alloc_result::invalid_coderate; ++nprb) {
prb_interval interv = find_empty_interval_of_length(prbs, nprb, start_prb_idx);
start_prb_idx = interv.stop();
start_prb_idx = interv.start();
if (interv.length() == nprb) {
ret = slot_grid.alloc_rar_and_msg3(
rar.ra_rnti, rar_aggr_level, interv, slot_ues, msg3_grants.subspan(0, nof_grants_alloc));
@ -67,20 +125,8 @@ void ra_sched::run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues)
{
slot_point pdcch_slot = slot_grid.get_pdcch_tti();
slot_point msg3_slot = pdcch_slot + bwp_cfg->pusch_ra_list[0].msg3_delay;
if (not slot_grid.res_grid()[pdcch_slot].is_dl) {
// RAR only allowed if PDCCH is available
return;
}
// Mark RAR window start, regardless of whether PUSCH is available
for (auto& rar : pending_rars) {
if (rar.rar_win.empty()) {
rar.rar_win = {pdcch_slot, pdcch_slot + bwp_cfg->cfg.rar_window_size};
}
}
if (not slot_grid.res_grid()[msg3_slot].is_ul) {
// RAR only allowed if respective Msg3 slot is available for UL
if (not bwp_cfg->slots[pdcch_slot.slot_idx()].is_dl or not bwp_cfg->slots[msg3_slot.slot_idx()].is_ul) {
// RAR only allowed if PDCCH is available and respective Msg3 slot is available for UL
return;
}
@ -137,13 +183,6 @@ void ra_sched::run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues)
/// See TS 38.321, 5.1.3 - RAP transmission
int ra_sched::dl_rach_info(const dl_sched_rar_info_t& rar_info)
{
logger.info("SCHED: New PRACH slot=%d, preamble=%d, temp_crnti=0x%x, ta_cmd=%d, msg3_size=%d",
rar_info.prach_slot.to_uint(),
rar_info.preamble_idx,
rar_info.temp_crnti,
rar_info.ta_cmd,
rar_info.msg3_size);
// RA-RNTI = 1 + s_id + 14 × t_id + 14 × 80 × f_id + 14 × 80 × 8 × ul_carrier_id
// s_id = index of the first OFDM symbol (0 <= s_id < 14)
// t_id = index of first slot of the PRACH (0 <= t_id < 80)
@ -151,6 +190,14 @@ int ra_sched::dl_rach_info(const dl_sched_rar_info_t& rar_info)
// ul_carrier_id = 0 for NUL and 1 for SUL carrier
uint16_t ra_rnti = 1 + rar_info.ofdm_symbol_idx + 14 * rar_info.prach_slot.slot_idx() + 14 * 80 * rar_info.freq_idx;
logger.info("SCHED: New PRACH slot=%d, preamble=%d, ra-rnti=0x%x, temp_crnti=0x%x, ta_cmd=%d, msg3_size=%d",
rar_info.prach_slot.to_uint(),
rar_info.preamble_idx,
ra_rnti,
rar_info.temp_crnti,
rar_info.ta_cmd,
rar_info.msg3_size);
// find pending rar with same RA-RNTI
for (pending_rar_t& r : pending_rars) {
if (r.prach_slot == rar_info.prach_slot and ra_rnti == r.ra_rnti) {
@ -165,8 +212,14 @@ int ra_sched::dl_rach_info(const dl_sched_rar_info_t& rar_info)
// create new RAR
pending_rar_t p;
p.ra_rnti = ra_rnti;
p.prach_slot = rar_info.prach_slot;
p.ra_rnti = ra_rnti;
p.prach_slot = rar_info.prach_slot;
const static uint32_t prach_duration = 1;
for (slot_point t = rar_info.prach_slot + prach_duration; t < rar_info.prach_slot + bwp_cfg->slots.size(); ++t) {
if (bwp_cfg->slots[t.slot_idx()].is_dl) {
p.rar_win = {t, t + bwp_cfg->cfg.rar_window_size};
}
}
p.msg3_grant.push_back(rar_info);
pending_rars.push_back(p);

@ -21,6 +21,7 @@
#include "srsenb/hdr/stack/mac/nr/sched_nr_cfg.h"
#include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h"
#include "srsran/adt/optional_array.h"
extern "C" {
#include "srsran/phy/phch/ra_ul_nr.h"
}
@ -36,6 +37,15 @@ bwp_params::bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, ui
P = get_P(cfg.rb_width, cfg.pdsch.rbg_size_cfg_1);
N_rbg = get_nof_rbgs(cfg.rb_width, cfg.start_rb, cfg.pdsch.rbg_size_cfg_1);
// Derive params of individual slots
uint32_t nof_slots = SRSRAN_NSLOTS_PER_FRAME_NR(cfg.numerology_idx);
for (size_t sl = 0; sl < nof_slots; ++sl) {
slot_cfg sl_cfg{};
sl_cfg.is_dl = srsran_tdd_nr_is_dl(&cell_cfg.tdd, cfg.numerology_idx, sl);
sl_cfg.is_ul = srsran_tdd_nr_is_ul(&cell_cfg.tdd, cfg.numerology_idx, sl);
slots.push_back(sl_cfg);
}
pusch_ra_list.resize(cfg.pusch.nof_common_time_ra);
const uint32_t coreset_id = 0;
srsran_sch_grant_nr_t grant;
@ -103,45 +113,40 @@ bwp_ue_cfg::bwp_ue_cfg(uint16_t rnti_, const bwp_params& bwp_cfg_, const ue_cfg_
rnti(rnti_), cfg_(&uecfg_), bwp_cfg(&bwp_cfg_)
{
std::fill(ss_id_to_cce_idx.begin(), ss_id_to_cce_idx.end(), SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE);
const auto& pdcch = phy().pdcch;
for (uint32_t i = 0; i < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++i) {
if (pdcch.search_space_present[i]) {
const auto& ss = pdcch.search_space[i];
srsran_assert(pdcch.coreset_present[ss.coreset_id],
"Invalid mapping search space id=%d to coreset id=%d",
ss.id,
ss.coreset_id);
const auto& coreset = pdcch.coreset[ss.coreset_id];
cce_positions_list.emplace_back();
get_dci_locs(coreset, ss, rnti, cce_positions_list.back());
ss_id_to_cce_idx[ss.id] = cce_positions_list.size() - 1;
}
const auto& pdcch = phy().pdcch;
auto ss_view = srsran::make_optional_span(pdcch.search_space, pdcch.search_space_present);
auto coreset_view = srsran::make_optional_span(pdcch.coreset, pdcch.coreset_present);
for (const auto& ss : ss_view) {
srsran_assert(coreset_view.contains(ss.coreset_id),
"Invalid mapping search space id=%d to coreset id=%d",
ss.id,
ss.coreset_id);
cce_positions_list.emplace_back();
get_dci_locs(coreset_view[ss.coreset_id], ss, rnti, cce_positions_list.back());
ss_id_to_cce_idx[ss.id] = cce_positions_list.size() - 1;
}
}
ue_cfg_extended::ue_cfg_extended(uint16_t rnti_, const ue_cfg_t& uecfg) : ue_cfg_t(uecfg), rnti(rnti_)
{
auto ss_view = srsran::make_optional_span(phy_cfg.pdcch.search_space, phy_cfg.pdcch.search_space_present);
auto coreset_view = srsran::make_optional_span(phy_cfg.pdcch.coreset, phy_cfg.pdcch.coreset_present);
cc_params.resize(carriers.size());
for (uint32_t cc = 0; cc < cc_params.size(); ++cc) {
cc_params[cc].bwps.resize(1);
auto& bwp = cc_params[cc].bwps[0];
for (uint32_t ssid = 0; ssid < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ++ssid) {
if (phy_cfg.pdcch.search_space_present[ssid]) {
auto& ss = phy_cfg.pdcch.search_space[ssid];
bwp.ss_list[ss.id].emplace();
bwp.ss_list[ss.id]->cfg = &ss;
get_dci_locs(phy_cfg.pdcch.coreset[ss.coreset_id], ss, rnti, bwp.ss_list[ss.id]->cce_positions);
}
for (auto& ss : ss_view) {
bwp.ss_list[ss.id].emplace();
bwp.ss_list[ss.id]->cfg = &ss;
get_dci_locs(phy_cfg.pdcch.coreset[ss.coreset_id], ss, rnti, bwp.ss_list[ss.id]->cce_positions);
}
for (uint32_t idx = 0; idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++idx) {
if (phy_cfg.pdcch.coreset_present[idx]) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &phy_cfg.pdcch.coreset[idx];
for (auto& ss : bwp.ss_list) {
if (ss.has_value() and ss->cfg->coreset_id == coreset.cfg->id) {
coreset.ss_list.push_back(ss->cfg->id);
}
for (auto& coreset_cfg : coreset_view) {
bwp.coresets.emplace_back();
auto& coreset = bwp.coresets.back();
coreset.cfg = &coreset_cfg;
for (auto& ss : bwp.ss_list) {
if (ss.has_value() and ss->cfg->coreset_id == coreset.cfg->id) {
coreset.ss_list.push_back(ss->cfg->id);
}
}
}

@ -26,15 +26,11 @@
namespace srsenb {
namespace sched_nr_impl {
#define NUMEROLOGY_IDX 0
bwp_slot_grid::bwp_slot_grid(const bwp_params& bwp_cfg_, uint32_t slot_idx_) :
dl_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1),
ul_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1),
slot_idx(slot_idx_),
cfg(&bwp_cfg_),
is_dl(srsran_tdd_nr_is_dl(&bwp_cfg_.cell_cfg.tdd, NUMEROLOGY_IDX, slot_idx_)),
is_ul(srsran_tdd_nr_is_ul(&bwp_cfg_.cell_cfg.tdd, NUMEROLOGY_IDX, slot_idx_))
cfg(&bwp_cfg_)
{
for (uint32_t cs_idx = 0; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++cs_idx) {
if (cfg->cfg.pdcch.coreset_present[cs_idx]) {
@ -73,6 +69,27 @@ bwp_slot_allocator::bwp_slot_allocator(bwp_res_grid& bwp_grid_) :
logger(srslog::fetch_basic_logger("MAC")), cfg(*bwp_grid_.cfg), bwp_grid(bwp_grid_)
{}
alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx, uint32_t si_idx, uint32_t si_ntx, const prb_interval& prbs)
{
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_slot];
if (not bwp_pdcch_slot.is_dl()) {
logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", bwp_pdcch_slot.slot_idx);
return alloc_result::no_sch_space;
}
pdcch_dl_list_t& pdsch_grants = bwp_pdcch_slot.dl_pdcchs;
if (pdsch_grants.full()) {
logger.warning("SCHED: Maximum number of DL allocations reached");
return alloc_result::no_grant_space;
}
if (bwp_pdcch_slot.dl_prbs.collides(prbs)) {
return alloc_result::sch_collision;
}
// TODO: Allocate PDCCH and PDSCH
return alloc_result::success;
}
alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t ra_rnti,
uint32_t aggr_idx,
prb_interval interv,
@ -140,15 +157,19 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
srsran_slot_cfg_t slot_cfg;
slot_cfg.idx = msg3_slot.slot_idx();
for (const dl_sched_rar_info_t& grant : pending_rars) {
slot_ue& ue = ues[grant.temp_crnti];
slot_ue& ue = ues[grant.temp_crnti];
// Allocate Msg3
prb_interval msg3_interv{last_msg3, last_msg3 + msg3_nof_prbs};
ue.h_ul = ue.harq_ent->find_empty_ul_harq();
bool success = ue.h_ul->new_tx(msg3_slot, msg3_slot, msg3_interv, mcs, 100, max_harq_msg3_retx);
srsran_assert(success, "Failed to allocate Msg3");
last_msg3 += msg3_nof_prbs;
pdcch_ul_t msg3_pdcch;
pdcch_ul_t msg3_pdcch; // dummy PDCCH for retx=0
fill_dci_msg3(ue, *bwp_grid.cfg, msg3_pdcch.dci);
msg3_pdcch.dci.time_domain_assigment = dai++;
// Generate PUSCH
bwp_msg3_slot.puschs.emplace_back();
pusch_t& pusch = bwp_msg3_slot.puschs.back();
success = ue.cfg->phy().get_pusch_cfg(slot_cfg, msg3_pdcch.dci, pusch.sch);
@ -175,7 +196,7 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr
bwp_slot_grid& bwp_pdcch_slot = bwp_grid[ue.pdcch_slot];
bwp_slot_grid& bwp_pdsch_slot = bwp_grid[ue.pdsch_slot];
bwp_slot_grid& bwp_uci_slot = bwp_grid[ue.uci_slot];
if (not bwp_pdsch_slot.is_dl) {
if (not bwp_pdsch_slot.is_dl()) {
logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", bwp_pdsch_slot.slot_idx);
return alloc_result::no_sch_space;
}
@ -308,13 +329,13 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const prb_grant& ul_pr
alloc_result bwp_slot_allocator::verify_pusch_space(bwp_slot_grid& pusch_grid, bwp_slot_grid* pdcch_grid) const
{
if (not pusch_grid.is_ul) {
if (not pusch_grid.is_ul()) {
logger.warning("SCHED: Trying to allocate PUSCH in TDD non-UL slot index=%d", pusch_grid.slot_idx);
return alloc_result::no_sch_space;
}
if (pdcch_grid != nullptr) {
// DCI needed
if (not pdcch_grid->is_dl) {
if (not pdcch_grid->is_dl()) {
logger.warning("SCHED: Trying to allocate PDCCH in TDD non-DL slot index=%d", pdcch_grid->slot_idx);
return alloc_result::no_sch_space;
}

@ -57,12 +57,16 @@ void fill_dci_common(const slot_ue& ue, const bwp_params& bwp_cfg, DciDlOrUl& dc
bool fill_dci_rar(prb_interval interv, uint16_t ra_rnti, const bwp_params& bwp_cfg, srsran_dci_dl_nr_t& dci)
{
dci.mcs = 5;
dci.ctx.format = srsran_dci_format_nr_rar;
dci.ctx.format = srsran_dci_format_nr_1_0;
dci.ctx.ss_type = srsran_search_space_type_rar;
dci.ctx.rnti_type = srsran_rnti_type_ra;
dci.ctx.rnti = ra_rnti;
dci.ctx.coreset_id = bwp_cfg.cfg.pdcch.ra_search_space.coreset_id;
dci.freq_domain_assigment = srsran_ra_nr_type1_riv(bwp_cfg.cfg.rb_width, interv.start(), interv.length());
dci.time_domain_assigment = 0;
dci.tpc = 1;
dci.bwp_id = bwp_cfg.bwp_id;
dci.cc_id = bwp_cfg.cc;
// TODO: Fill
return true;
@ -70,6 +74,7 @@ bool fill_dci_rar(prb_interval interv, uint16_t ra_rnti, const bwp_params& bwp_c
bool fill_dci_msg3(const slot_ue& ue, const bwp_params& bwp_cfg, srsran_dci_ul_nr_t& msg3_dci)
{
fill_dci_common(ue, bwp_cfg, msg3_dci);
msg3_dci.ctx.coreset_id = ue.cfg->phy().pdcch.ra_search_space.coreset_id;
msg3_dci.ctx.rnti_type = srsran_rnti_type_tc;
msg3_dci.ctx.rnti = ue.rnti;
@ -79,7 +84,6 @@ bool fill_dci_msg3(const slot_ue& ue, const bwp_params& bwp_cfg, srsran_dci_ul_n
} else {
msg3_dci.ctx.format = srsran_dci_format_nr_0_0;
}
fill_dci_common(ue, bwp_cfg, msg3_dci);
return true;
}

@ -145,20 +145,21 @@ void slot_cc_worker::log_result() const
fmt::memory_buffer fmtbuf;
if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) {
const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti];
fmt::format_to(fmtbuf,
"SCHED: DL {}, cc={}, rnti=0x{:x}, pid={}, f={}, nrtx={}, dai={}, tbs={}, tti_pdsch={}, tti_ack={}",
ue.h_dl->nof_retx() == 0 ? "tx" : "retx",
cell.cfg.cc,
ue.rnti,
pdcch.dci.pid,
srsran_dci_format_nr_string(pdcch.dci.ctx.format),
ue.h_dl->nof_retx(),
pdcch.dci.dai,
ue.h_dl->tbs(),
ue.pdsch_slot,
ue.uci_slot);
fmt::format_to(
fmtbuf,
"SCHED: DL {}, cc={}, rnti=0x{:x}, pid={}, f={}, nrtx={}, dai={}, tbs={}, tti_pdsch={}, tti_ack={}",
ue.h_dl->nof_retx() == 0 ? "tx" : "retx",
cell.cfg.cc,
ue.rnti,
pdcch.dci.pid,
srsran_dci_format_nr_string(pdcch.dci.ctx.format),
ue.h_dl->nof_retx(),
pdcch.dci.dai,
ue.h_dl->tbs(),
ue.pdsch_slot,
ue.uci_slot);
} else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) {
fmt::format_to(fmtbuf, "SCHED: DL RAR, cc={}", cell.cfg.cc);
fmt::format_to(fmtbuf, "SCHED: DL RAR, cc={}, ra-rnti=0x{:x}", cell.cfg.cc, pdcch.dci.ctx.rnti);
} else {
fmt::format_to(fmtbuf, "SCHED: unknown format");
}

@ -688,13 +688,21 @@ void rrc::ue::rrc_mobility::s1_source_ho_st::handle_ho_cmd(wait_ho_cmd& s, const
rrc_ue->mac_ctrl.update_mac(mac_controller::proc_stage_t::other);
// Send HO Command to UE
if (not rrc_ue->send_dl_dcch(&dl_dcch_msg)) {
std::string octet_str;
if (not rrc_ue->send_dl_dcch(&dl_dcch_msg, nullptr, &octet_str)) {
asn1::s1ap::cause_c cause;
cause.set_protocol().value = asn1::s1ap::cause_protocol_opts::unspecified;
trigger(ho_cancel_ev{cause});
return;
}
// Log rrc release event.
event_logger::get().log_rrc_event(rrc_ue->ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX)->cell_common->enb_cc_idx,
octet_str,
static_cast<unsigned>(rrc_event_type::con_reconf),
static_cast<unsigned>(procedure_result_code::none),
rrc_ue->rnti);
/* Start S1AP eNBStatusTransfer Procedure */
asn1::s1ap::cause_c cause = start_enb_status_transfer(*ho_cmd.s1ap_ho_cmd);
if (cause.type().value != asn1::s1ap::cause_c::types_opts::nulltype) {

@ -27,11 +27,11 @@
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srsran/asn1/rrc_utils.h"
#include "srsran/common/enb_events.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h"
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/enb_s1ap_interfaces.h"
#include "srsran/support/srsran_assert.h"
using namespace asn1::rrc;
@ -1429,7 +1429,7 @@ void rrc::ue::apply_rlc_rb_updates(const rr_cfg_ded_s& pending_rr_cfg)
} else if (srb.srb_id == 2) {
srb_cfg = &parent->cfg.srb2_cfg;
} else {
srsran_terminate("Invalid LTE SRB id=%d", srb.srb_id);
srsran_assertion_failure("Invalid LTE SRB id=%d", srb.srb_id);
}
if (srb_cfg->rlc_cfg.type() == srb_to_add_mod_s::rlc_cfg_c_::types_opts::explicit_value) {

@ -558,7 +558,7 @@ bool s1ap::handle_mme_rx_msg(srsran::unique_byte_buffer_t pdu,
if (flags & MSG_NOTIFICATION) {
// Received notification
union sctp_notification* notification = (union sctp_notification*)pdu->msg;
logger.debug("SCTP Notification %d", notification->sn_header.sn_type);
logger.info("SCTP Notification %04x", notification->sn_header.sn_type);
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) {
logger.info("SCTP Association Shutdown. Association: %d", sri.sinfo_assoc_id);
srsran::console("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);

@ -22,11 +22,11 @@
#include "srsran/upper/gtpu.h"
#include "srsenb/hdr/stack/upper/gtpu.h"
#include "srsran/common/network_utils.h"
#include "srsran/common/srsran_assert.h"
#include "srsran/common/standard_streams.h"
#include "srsran/common/string_helpers.h"
#include "srsran/interfaces/enb_interfaces.h"
#include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/support/srsran_assert.h"
#include <errno.h>
#include <linux/ip.h>

@ -23,7 +23,7 @@
#include "srsenb/hdr/stack/mac/sched_lte_common.h"
#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h"
#include "srsran/common/common_lte.h"
#include "srsran/common/test_common.h"
#include "srsran/support/srsran_test.h"
namespace srsenb {
@ -260,7 +260,7 @@ int test_min_mcs_tbs_specific()
CONDERROR(result.tbs_bytes * 8 != 120, "Invalid min TBS calculation");
args.req_bytes = 50;
TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSRAN_SUCCESS);
TESTASSERT_SUCCESS(test_min_mcs_tbs_dl_helper(cell_params, args, &result));
CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation");
CONDERROR(result.tbs_bytes * 8 != 424, "Invalid min TBS calculation");
@ -273,7 +273,7 @@ int test_min_mcs_tbs_specific()
// Check equality case
args.req_bytes = 109;
TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSRAN_SUCCESS);
TESTASSERT_SUCCESS(test_min_mcs_tbs_dl_helper(cell_params, args, &result));
CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation");
CONDERROR(result.tbs_bytes * 8 != 872, "Invalid min TBS calculation");
@ -303,18 +303,18 @@ void test_ul_mcs_tbs_derivation()
};
cqi = 0;
TESTASSERT(compute_tbs_mcs(25, 25 - 4).mcs == 0);
TESTASSERT(compute_tbs_mcs(50, 50 - 5).mcs == 0);
TESTASSERT_EQ(0, compute_tbs_mcs(25, 25 - 4).mcs);
TESTASSERT_EQ(0, compute_tbs_mcs(50, 50 - 5).mcs);
cqi = 5;
TESTASSERT(compute_tbs_mcs(25, 25 - 4).mcs == 9);
TESTASSERT(compute_tbs_mcs(50, 50 - 5).mcs == 9);
TESTASSERT_EQ(9, compute_tbs_mcs(25, 25 - 4).mcs);
TESTASSERT_EQ(9, compute_tbs_mcs(50, 50 - 5).mcs);
cqi = 15;
TESTASSERT(compute_tbs_mcs(25, 25 - 4).mcs == 23);
TESTASSERT(compute_tbs_mcs(50, 50 - 5).mcs == 23);
TESTASSERT(compute_tbs_mcs(75, 75 - 5).mcs == 24);
TESTASSERT(compute_tbs_mcs(100, 100 - 5).mcs == 23);
TESTASSERT_EQ(23, compute_tbs_mcs(25, 25 - 4).mcs);
TESTASSERT_EQ(23, compute_tbs_mcs(50, 50 - 5).mcs);
TESTASSERT_EQ(24, compute_tbs_mcs(75, 75 - 5).mcs);
TESTASSERT_EQ(23, compute_tbs_mcs(100, 100 - 5).mcs);
}
} // namespace srsenb

@ -358,8 +358,19 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out)
// TEST: No UL allocs except for Msg3 before Msg4
for (uint32_t i = 0; i < ul_cc_res.pusch.size(); ++i) {
if (ul_cc_res.pusch[i].dci.rnti == rnti) {
CONDERROR(not ue.rar_tti_rx.is_valid(), "No UL allocs before RAR allowed");
srsran::tti_point expected_msg3_tti = ue.rar_tti_rx + MSG3_DELAY_MS;
tti_point rar_tti_rx = ue.rar_tti_rx;
if (not rar_tti_rx.is_valid()) {
for (uint32_t j = 0; j < dl_cc_res.rar.size(); ++j) {
for (const auto& grant : dl_cc_res.rar[i].msg3_grant) {
if (grant.data.temp_crnti == ue.rnti) {
rar_tti_rx = sf_out.tti_rx;
break;
}
}
}
}
CONDERROR(not rar_tti_rx.is_valid(), "No UL allocs before RAR allowed");
srsran::tti_point expected_msg3_tti = rar_tti_rx + MSG3_DELAY_MS;
CONDERROR(expected_msg3_tti > sf_out.tti_rx, "No UL allocs before Msg3 is scheduled");
if (expected_msg3_tti < sf_out.tti_rx) {
bool msg3_retx =

@ -25,6 +25,7 @@
#include "rrc_cell.h"
#include "rrc_common.h"
#include "rrc_metrics.h"
#include "rrc_rlf_report.h"
#include "srsran/asn1/rrc_utils.h"
#include "srsran/common/bcd_helpers.h"
#include "srsran/common/block_queue.h"
@ -227,6 +228,9 @@ private:
const char* get_rb_name(uint32_t lcid) { return srsran::is_lte_rb(lcid) ? rb_id_str[lcid].c_str() : "invalid RB"; }
// Var-RLF-Report class
rrc_rlf_report var_rlf_report;
// Measurements private subclass
class rrc_meas;
std::unique_ptr<rrc_meas> measurements;
@ -384,6 +388,7 @@ private:
void handle_con_reest(const asn1::rrc::rrc_conn_reest_s& setup);
void handle_rrc_con_reconfig(uint32_t lcid, const asn1::rrc::rrc_conn_recfg_s& reconfig);
void handle_ue_capability_enquiry(const asn1::rrc::ue_cap_enquiry_s& enquiry);
void handle_ue_info_request(const ue_info_request_r9_s& request);
void add_srb(const asn1::rrc::srb_to_add_mod_s& srb_cnfg);
void add_drb(const asn1::rrc::drb_to_add_mod_s& drb_cnfg);
void release_drb(uint32_t drb_id);

@ -156,6 +156,7 @@ public:
bool has_plmn_id(asn1::rrc::plmn_id_s plmn_id) const;
uint32_t nof_plmns() const { return has_sib1() ? sib1.cell_access_related_info.plmn_id_list.size() : 0; }
srsran::plmn_id_t get_plmn(uint32_t idx) const;
asn1::rrc::plmn_id_s get_plmn_asn1(uint32_t idx) const;
uint16_t get_tac() const { return has_sib1() ? (uint16_t)sib1.cell_access_related_info.tac.to_number() : 0; }
@ -170,6 +171,7 @@ public:
const asn1::rrc::sib_type13_r9_s* sib13ptr() const { return has_sib13() ? &sib13 : nullptr; }
uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); }
asn1::fixed_bitstring<28> get_cell_id_bit() const { return sib1.cell_access_related_info.cell_id; }
bool has_sib13() const { return has_valid_sib13; }

@ -24,6 +24,8 @@
namespace srsue {
#include <stdint.h>
// RRC states (3GPP 36.331 v10.0.0)
typedef enum {
RRC_STATE_IDLE = 0,
@ -32,6 +34,11 @@ typedef enum {
} rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", "CONNECTED"};
enum quant_s { quant_rsrp, quant_rsrq };
uint8_t rrc_value_to_range(quant_s quant, const float value);
float rrc_range_to_value(quant_s quant, const uint8_t range);
} // namespace srsue
#endif // SRSUE_RRC_COMMON_H

@ -201,8 +201,6 @@ private:
rrc* rrc_ptr = nullptr;
// Static functions
static uint8_t value_to_range(const report_cfg_eutra_s::trigger_quant_opts::options q, float value);
static float range_to_value(const report_cfg_eutra_s::trigger_quant_opts::options q, const uint8_t range);
static uint8_t value_to_range_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const float value);
static float range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range);
static uint8_t offset_val(const meas_obj_eutra_s& meas_obj);

@ -0,0 +1,58 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_RRC_RLF_REPORT_H_
#define SRSRAN_RRC_RLF_REPORT_H_
#include "rrc_cell.h"
#include "srsran/asn1/rrc.h"
#include "srsran/common/common.h"
namespace srsue {
using namespace asn1::rrc;
// RRC RLF-Report class
class rrc_rlf_report
{
public:
enum failure_type_t { rlf, hof };
void init(srsran::task_sched_handle task_sched);
// Returns true if VarRLF-Report structure has info available
bool has_info();
// Called upon T304 expiry (type == hof) or Detection of radio link failure (type == rlf)
void set_failure(meas_cell_list<meas_cell_eutra>& meas_cells, failure_type_t type);
// Called upon transmission of ReestablishmentRequest message
void set_reest_gci(const asn1::fixed_bitstring<28>& gci, const asn1::rrc::plmn_id_s& plmn_id);
// Called upon initiation of RadioReconfiguration message including MobilityInfo IE
void received_ho_command(const asn1::fixed_bitstring<28>& current_gci);
// Returns a copy of the rlf_report_r9 ASN1 struct
rlf_report_r9_s get_report();
// Clears VarRLF-Report contents
void clear();
private:
asn1::fixed_bitstring<28> ho_gci;
bool has_event = false;
rlf_report_r9_s rlf_report = {};
srsran::timer_handler::unique_timer timer_conn_failure = {};
};
} // namespace srsue
#endif // SRSRAN_RRC_RLF_REPORT_H_

@ -185,7 +185,7 @@ void cc_worker::decode_pdcch_dl()
for (uint32_t i = 0; i < ue_dl.pdcch_info_count; i++) {
const srsran_ue_dl_nr_pdcch_info_t* info = &ue_dl.pdcch_info[i];
logger.debug("PDCCH: dci=%s, rnti=%x, crst_id=%d, ss_type=%d, ncce=%d, al=%d, EPRE=%+.2f, RSRP=%+.2f, corr=%.3f; "
"nof_bits=%d; crc=%s;",
"evm=%f; nof_bits=%d; crc=%s;",
srsran_dci_format_nr_string(info->dci_ctx.format),
info->dci_ctx.rnti,
info->dci_ctx.coreset_id,
@ -195,6 +195,7 @@ void cc_worker::decode_pdcch_dl()
info->measure.epre_dBfs,
info->measure.rsrp_dBfs,
info->measure.norm_corr,
info->result.evm,
info->nof_bits,
info->result.crc ? "OK" : "KO");
}

@ -22,8 +22,8 @@
#include "srsran/asn1/rrc/rr_common.h"
#include "srsran/asn1/rrc_utils.h"
#include "srsran/common/mac_pcap.h"
#include "srsran/common/test_common.h"
#include "srsran/common/tsan_options.h"
#include "srsran/support/srsran_test.h"
#include "srsran/test/ue_test_interfaces.h"
#include "srsue/hdr/stack/mac/mac.h"
#include "srsue/hdr/stack/mac/mux.h"

@ -20,7 +20,7 @@
add_subdirectory(test)
set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc phy_controller.cc)
set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc rrc_common.cc rrc_rlf_report.cc phy_controller.cc)
add_library(srsue_rrc STATIC ${SOURCES})
set(SOURCES rrc_nr.cc)

@ -148,6 +148,8 @@ void rrc::init(phy_interface_rrc_lte* phy_,
t311 = task_sched.get_unique_timer();
t304 = task_sched.get_unique_timer();
var_rlf_report.init(task_sched);
transaction_id = 0;
cell_clean_cnt = 0;
@ -683,6 +685,9 @@ void rrc::radio_link_failure_process()
// TODO: Generate and store failure report
srsran::console("Warning: Detected Radio-Link Failure\n");
// Store the information in VarRLF-Report
var_rlf_report.set_failure(meas_cells, rrc_rlf_report::rlf);
if (state == RRC_STATE_CONNECTED) {
if (security_is_activated) {
logger.info("Detected Radio-Link Failure with active AS security. Starting ConnectionReestablishment...");
@ -866,6 +871,9 @@ void rrc::send_con_restablish_request(reest_cause_e cause, uint16_t crnti, uint1
// Clean reestablishment type
reestablishment_successful = false;
// set the reestablishmentCellId in the VarRLF-Report to the global cell identity of the selected cell;
var_rlf_report.set_reest_gci(meas_cells.serving_cell().get_cell_id_bit(), meas_cells.serving_cell().get_plmn_asn1(0));
if (cause.value != reest_cause_opts::ho_fail) {
if (cause.value != reest_cause_opts::other_fail) {
pci = meas_cells.serving_cell().get_pci();
@ -954,6 +962,15 @@ void rrc::send_con_restablish_complete()
ul_dcch_msg.msg.set_c1().set_rrc_conn_reest_complete().crit_exts.set_rrc_conn_reest_complete_r8();
ul_dcch_msg.msg.c1().rrc_conn_reest_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
ul_dcch_msg.msg.c1().rrc_conn_reest_complete().crit_exts.rrc_conn_reest_complete_r8().non_crit_ext_present = true;
ul_dcch_msg.msg.c1()
.rrc_conn_reest_complete()
.crit_exts.rrc_conn_reest_complete_r8()
.non_crit_ext.rlf_info_available_r9_present = true;
}
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
reestablishment_successful = true;
@ -970,6 +987,13 @@ void rrc::send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg)
ul_dcch_msg.msg.c1().rrc_conn_setup_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
rrc_conn_setup_complete->non_crit_ext_present = true;
rrc_conn_setup_complete->non_crit_ext.non_crit_ext_present = true;
rrc_conn_setup_complete->non_crit_ext.non_crit_ext.rlf_info_available_r10_present = true;
}
rrc_conn_setup_complete->sel_plmn_id = 1;
rrc_conn_setup_complete->ded_info_nas.resize(nas_msg->N_bytes);
memcpy(rrc_conn_setup_complete->ded_info_nas.data(), nas_msg->msg, nas_msg->N_bytes); // TODO Check!
@ -1014,6 +1038,13 @@ void rrc::send_rrc_con_reconfig_complete(bool contains_nr_complete)
&ul_dcch_msg.msg.set_c1().set_rrc_conn_recfg_complete().crit_exts.set_rrc_conn_recfg_complete_r8();
ul_dcch_msg.msg.c1().rrc_conn_recfg_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
rrc_conn_recfg_complete_r8->non_crit_ext_present = true;
rrc_conn_recfg_complete_r8->non_crit_ext.non_crit_ext_present = true;
rrc_conn_recfg_complete_r8->non_crit_ext.non_crit_ext.rlf_info_available_r10_present = true;
}
if (contains_nr_complete == true) {
logger.debug("Preparing RRC Connection Reconfig Complete with NR Complete");
@ -1064,6 +1095,10 @@ void rrc::start_go_idle()
void rrc::ho_failed()
{
ho_handler.trigger(ho_proc::t304_expiry{});
// Store the information in VarRLF-Report
var_rlf_report.set_failure(meas_cells, rrc_rlf_report::hof);
start_con_restablishment(reest_cause_e::ho_fail);
}
@ -1766,6 +1801,10 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release:
rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string());
break;
case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9:
transaction_id = c1->ue_info_request_r9().rrc_transaction_id;
handle_ue_info_request(c1->ue_info_request_r9());
break;
default:
logger.error("The provided DL-CCCH message type is not recognized or supported");
break;
@ -2145,6 +2184,42 @@ void rrc::handle_ue_capability_enquiry(const ue_cap_enquiry_s& enquiry)
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
}
/*******************************************************************************
*
*
*
* UEInformationRequest message
*
*
*
*******************************************************************************/
void rrc::handle_ue_info_request(const ue_info_request_r9_s& request)
{
logger.debug("Preparing UEInformationResponse message");
ul_dcch_msg_s ul_dcch_msg;
ue_info_resp_r9_ies_s* resp =
&ul_dcch_msg.msg.set_c1().set_ue_info_resp_r9().crit_exts.set_c1().set_ue_info_resp_r9();
ul_dcch_msg.msg.c1().ue_info_resp_r9().rrc_transaction_id = transaction_id;
// if rach-ReportReq is set to true, set the contents of the rach-Report in the UEInformationResponse message as
// follows
if (request.crit_exts.c1().ue_info_request_r9().rach_report_req_r9) {
// todo...
}
// Include rlf-Report if rlf-ReportReq is set to true
if (request.crit_exts.c1().ue_info_request_r9().rlf_report_req_r9 && var_rlf_report.has_info()) {
resp->rlf_report_r9_present = true;
resp->rlf_report_r9 = var_rlf_report.get_report();
// fixme: should be cleared upon successful delivery
var_rlf_report.clear();
}
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
}
/*******************************************************************************
*
*

@ -42,6 +42,15 @@ srsran::plmn_id_t meas_cell_eutra::get_plmn(uint32_t idx) const
}
}
asn1::rrc::plmn_id_s meas_cell_eutra::get_plmn_asn1(uint32_t idx) const
{
if (idx < sib1.cell_access_related_info.plmn_id_list.size() && has_valid_sib1) {
return sib1.cell_access_related_info.plmn_id_list[idx].plmn_id;
} else {
return {};
}
}
void meas_cell_eutra::set_sib1(const asn1::rrc::sib_type1_s& sib1_)
{
sib1 = sib1_;

@ -0,0 +1,51 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsue/hdr/stack/rrc/rrc_common.h"
namespace srsue {
uint8_t rrc_value_to_range(quant_s quant, const float value)
{
uint8_t range = 0;
if (quant == quant_rsrp) {
if (value < -140) {
range = 0;
} else if (value < -44) {
range = 1u + (uint8_t)(value + 140);
} else {
range = 97;
}
} else {
if (value < -19.5) {
range = 0;
} else if (value < -3) {
range = 1u + (uint8_t)(2 * (value + 19.5));
} else {
range = 34;
}
}
return range;
}
float rrc_range_to_value(quant_s quant, const uint8_t range)
{
float val = 0;
if (quant == quant_rsrp) {
val = -140 + (float)range;
} else {
val = -19.5f + (float)range / 2;
}
return val;
}
} // namespace srsue

@ -139,50 +139,6 @@ void rrc::rrc_meas::run_tti()
meas_cfg.report_triggers();
}
uint8_t rrc::rrc_meas::value_to_range(const report_cfg_eutra_s::trigger_quant_opts::options quant, const float value)
{
uint8_t range = 0;
switch (quant) {
case report_cfg_eutra_s::trigger_quant_opts::rsrp:
if (value < -140) {
range = 0;
} else if (value < -44) {
range = 1u + (uint8_t)(value + 140);
} else {
range = 97;
}
break;
case report_cfg_eutra_s::trigger_quant_opts::rsrq:
if (value < -19.5) {
range = 0;
} else if (value < -3) {
range = 1u + (uint8_t)(2 * (value + 19.5));
} else {
range = 34;
}
break;
default:
break;
}
return range;
}
float rrc::rrc_meas::range_to_value(const report_cfg_eutra_s::trigger_quant_opts::options quant, const uint8_t range)
{
float val = 0;
switch (quant) {
case report_cfg_eutra_s::trigger_quant_opts::rsrp:
val = -140 + (float)range;
break;
case report_cfg_eutra_s::trigger_quant_opts::rsrq:
val = -19.5f + (float)range / 2;
break;
default:
break;
}
return val;
}
// For thresholds, the actual value is (field value 156) dBm, except for field value 127, in which case the actual
// value is infinity.
float rrc::rrc_meas::range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range)
@ -312,8 +268,8 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_eutra(meas_results_s*
break;
}
rc.pci = (uint16_t)cell.pci;
rc.meas_result.rsrp_result = value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrp, rsrp_value);
rc.meas_result.rsrq_result = value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrq, rsrq_value);
rc.meas_result.rsrp_result = rrc_value_to_range(quant_rsrp, rsrp_value);
rc.meas_result.rsrq_result = rrc_value_to_range(quant_rsrq, rsrq_value);
logger.info("MEAS: Adding to report neighbour=%d, pci=%d, earfcn=%d, rsrp=%+.1f, rsrq=%+.1f",
neigh_list.size(),
@ -457,10 +413,8 @@ void rrc::rrc_meas::var_meas_report_list::generate_report(const uint32_t measId)
meas_results_s* report = &ul_dcch_msg.msg.c1().meas_report().crit_exts.c1().meas_report_r8().meas_results;
report->meas_id = (uint8_t)measId;
report->meas_result_pcell.rsrp_result =
value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrp, serv_cell->get_rsrp());
report->meas_result_pcell.rsrq_result =
value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrq, serv_cell->get_rsrq());
report->meas_result_pcell.rsrp_result = rrc_value_to_range(quant_rsrp, serv_cell->get_rsrp());
report->meas_result_pcell.rsrq_result = rrc_value_to_range(quant_rsrq, serv_cell->get_rsrq());
logger.info("MEAS: Generate report MeasId=%d, Pcell rsrp=%f rsrq=%f",
report->meas_id,
@ -814,6 +768,14 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
float Ofs,
float Ocs)
{
auto asn1_quant_convert = [](report_cfg_eutra_s::trigger_quant_e_ q) {
if (q == report_cfg_eutra_s::trigger_quant_opts::rsrp) {
return quant_rsrp;
} else {
return quant_rsrq;
}
};
double hyst = 0.5 * report_cfg.trigger_type.event().hysteresis;
float Ms = is_rsrp(report_cfg.trigger_quant.value) ? serv_cell->get_rsrp() : serv_cell->get_rsrq();
@ -832,17 +794,21 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
bool exit_condition = false;
if (event_id.type() == eutra_event_s::event_id_c_::types::event_a1) {
if (event_id.event_a1().a1_thres.type().value == thres_eutra_c::types::thres_rsrp) {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a1().a1_thres.thres_rsrp());
thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a1().a1_thres.thres_rsrp());
} else {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a1().a1_thres.thres_rsrq());
thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a1().a1_thres.thres_rsrq());
}
enter_condition = Ms - hyst > thresh;
exit_condition = Ms + hyst < thresh;
} else {
if (event_id.event_a2().a2_thres.type() == thres_eutra_c::types::thres_rsrp) {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a2().a2_thres.thres_rsrp());
thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a2().a2_thres.thres_rsrp());
} else {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a2().a2_thres.thres_rsrq());
thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a2().a2_thres.thres_rsrq());
}
enter_condition = Ms + hyst < thresh;
exit_condition = Ms - hyst > thresh;
@ -893,7 +859,7 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
} else {
range = event_id.event_a4().a4_thres.thres_rsrq();
}
thresh = range_to_value(report_cfg.trigger_quant.value, range);
thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range);
enter_condition = Mn + Ofn + Ocn - hyst > thresh;
exit_condition = Mn + Ofn + Ocn + hyst < thresh;
break;
@ -908,8 +874,8 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
} else {
range2 = event_id.event_a5().a5_thres2.thres_rsrq();
}
th1 = range_to_value(report_cfg.trigger_quant.value, range);
th2 = range_to_value(report_cfg.trigger_quant.value, range2);
th1 = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range);
th2 = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range2);
enter_condition = (Ms + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2);
exit_condition = (Ms - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2);
break;
@ -1479,19 +1445,18 @@ void rrc::rrc_meas::var_meas_cfg::log_debug_trigger_value_eutra(const eutra_even
switch (e.type()) {
case eutra_event_s::event_id_c_::types_opts::event_a1:
logger.debug("MEAS: A1-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a1().a1_thres.thres_rsrp()));
rrc_range_to_value(quant_rsrp, e.event_a1().a1_thres.thres_rsrp()));
break;
case eutra_event_s::event_id_c_::types_opts::event_a2:
logger.debug("MEAS: A2-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a2().a2_thres.thres_rsrp()));
rrc_range_to_value(quant_rsrp, e.event_a2().a2_thres.thres_rsrp()));
break;
case eutra_event_s::event_id_c_::types_opts::event_a3:
logger.debug("MEAS: A3-offset=%.1f dB",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a3().a3_offset));
logger.debug("MEAS: A3-offset=%.1f dB", rrc_range_to_value(quant_rsrp, e.event_a3().a3_offset));
break;
case eutra_event_s::event_id_c_::types_opts::event_a4:
logger.debug("MEAS: A4-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a4().a4_thres.thres_rsrp()));
rrc_range_to_value(quant_rsrp, e.event_a4().a4_thres.thres_rsrp()));
break;
default:
logger.debug("MEAS: Unsupported");
@ -1606,7 +1571,7 @@ bool rrc::rrc_meas::var_meas_cfg::parse_meas_config(const meas_cfg_s* cfg, bool
// set the parameter s-Measure within VarMeasConfig to the lowest value of the RSRP ranges indicated by the
// received value of s-Measure
if (cfg->s_measure) {
s_measure_value = range_to_value(report_cfg_eutra_s::trigger_quant_opts::options::rsrp, cfg->s_measure);
s_measure_value = rrc_range_to_value(quant_rsrp, cfg->s_measure);
}
}

@ -1665,6 +1665,9 @@ srsran::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc
rrc_ptr->t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { rrc_ptr->timer_expired(tid); });
rrc_ptr->t304.run();
// Indicate RLF-Report that a new HO has been received
rrc_ptr->var_rlf_report.received_ho_command(rrc_ptr->meas_cells.serving_cell().get_cell_id_bit());
// starting at start synchronising to the DL of the target PCell
rrc_ptr->set_serving_cell(target_cell, false);
Info("Starting cell selection of target cell PCI=%d EARFCN=%d", target_cell.pci, target_cell.earfcn);

@ -0,0 +1,136 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsue/hdr/stack/rrc/rrc_rlf_report.h"
#include "srsue/hdr/stack/rrc/rrc_common.h"
namespace srsue {
void rrc_rlf_report::init(srsran::task_sched_handle task_sched)
{
timer_conn_failure = task_sched.get_unique_timer();
}
// Returns true if VarRLF-Report structure has info available
bool rrc_rlf_report::has_info()
{
return has_event;
}
// Called upon T304 expiry (type == hof) or Detection of radio link failure (type == rlf)
void rrc_rlf_report::set_failure(meas_cell_list<meas_cell_eutra>& meas_cells, failure_type_t type)
{
has_event = true;
// clear the information included in VarRLF-Report, if any
rlf_report = {};
// set the plmn-Identity to the RPLMN
// set the measResultLastServCell to include the RSRP and RSRQ, if available, of the PCell based on
// measurements collected up to the moment the UE detected radio link failure
rlf_report.meas_result_last_serv_cell_r9.rsrp_result_r9 =
rrc_value_to_range(quant_rsrp, meas_cells.serving_cell().get_rsrp());
rlf_report.meas_result_last_serv_cell_r9.rsrq_result_r9 =
rrc_value_to_range(quant_rsrq, meas_cells.serving_cell().get_rsrq());
rlf_report.meas_result_last_serv_cell_r9.rsrq_result_r9_present = true;
// set the measResultNeighCells to include the best measured cells, other than the PCell, ordered such that
// the best cell is listed first, and based on measurements collected up to the moment the UE detected radio
// link failure
if (meas_cells.nof_neighbours() > 0) {
rlf_report.meas_result_neigh_cells_r9_present = true;
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present = true;
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.clear();
meas_cells.sort_neighbour_cells();
// It is not clear how the sorting and grouping of cells per frequency must be done.
// We use a separate MeasResultList2EUTRA-r9 struct for each pci/frequency pair
for (const auto& f : meas_cells) {
meas_result2_eutra_r9_s meas2 = {};
meas2.carrier_freq_r9 = f->get_earfcn();
meas_result_eutra_s meas = {};
meas.pci = f->get_pci();
meas.meas_result.rsrp_result_present = true;
meas.meas_result.rsrq_result_present = true;
meas.meas_result.rsrp_result = rrc_value_to_range(quant_rsrp, f->get_rsrp());
meas.meas_result.rsrq_result = rrc_value_to_range(quant_rsrq, f->get_rsrq());
meas2.meas_result_list_r9.push_back(meas);
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.push_back(meas2);
}
}
// set the failedPCellId to the global cell identity, if available, and otherwise to the physical cell identity and
// carrier frequency of the PCell where radio link failure is detected;
rlf_report.failed_pcell_id_r10.set_present(true);
if (meas_cells.serving_cell().has_sib1()) {
rlf_report.failed_pcell_id_r10->set_cell_global_id_r10().cell_id = meas_cells.serving_cell().get_cell_id_bit();
rlf_report.failed_pcell_id_r10->cell_global_id_r10().plmn_id = meas_cells.serving_cell().get_plmn_asn1(0);
} else {
rlf_report.failed_pcell_id_r10->set_pci_arfcn_r10();
rlf_report.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 = meas_cells.serving_cell().get_pci();
rlf_report.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = meas_cells.serving_cell().get_earfcn();
}
// if an RRCConnectionReconfiguration message including the mobilityControlInfo was received before the
// connection failure
if (timer_conn_failure.is_running()) {
timer_conn_failure.stop();
// include previousPCellId and set it to the global cell identity of the PCell where the last
// RRCConnectionReconfiguration including the mobilityControlInfo message was received;
rlf_report.prev_pcell_id_r10.set_present(true);
rlf_report.prev_pcell_id_r10->cell_id = ho_gci;
rlf_report.prev_pcell_id_r10->plmn_id = meas_cells.serving_cell().get_plmn_asn1(0);
// set the timeConnFailure to the elapsed time since reception of the last
// RRCConnectionReconfiguration message including the mobilityControlInfo;
rlf_report.time_conn_fail_r10_present = true;
rlf_report.time_conn_fail_r10 = timer_conn_failure.time_elapsed() / 100; // 1 unit = 100 ms
}
// set the connectionFailureType
rlf_report.conn_fail_type_r10_present = true;
rlf_report.conn_fail_type_r10 =
type == rlf ? rlf_report_r9_s::conn_fail_type_r10_opts::rlf : rlf_report_r9_s::conn_fail_type_r10_opts::hof;
rlf_report.ext = true;
}
void rrc_rlf_report::set_reest_gci(const asn1::fixed_bitstring<28>& gci, const asn1::rrc::plmn_id_s& plmn_id)
{
rlf_report.reest_cell_id_r10.set_present(true);
rlf_report.reest_cell_id_r10->cell_id = gci;
rlf_report.reest_cell_id_r10->plmn_id = plmn_id;
}
void rrc_rlf_report::received_ho_command(const asn1::fixed_bitstring<28>& current_gci)
{
if (timer_conn_failure.is_valid()) {
timer_conn_failure.stop();
timer_conn_failure.run();
ho_gci = current_gci;
}
}
rlf_report_r9_s rrc_rlf_report::get_report()
{
return rlf_report;
}
// Clears VarRLF-Report contents
void rrc_rlf_report::clear()
{
has_event = false;
rlf_report = {};
}
} // namespace srsue

@ -34,6 +34,10 @@ add_executable(rrc_cell_test rrc_cell_test.cc)
target_link_libraries(rrc_cell_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)
add_test(rrc_cell_test rrc_cell_test)
add_executable(rrc_rlf_report_test rrc_rlf_report_test.cc)
target_link_libraries(rrc_rlf_report_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)
add_test(rrc_rlf_report_test rrc_rlf_report_test)
add_executable(ue_rrc_nr_test ue_rrc_nr_test.cc)
target_link_libraries(ue_rrc_nr_test srsue_rrc_nr srsue_upper srsran_common srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)

@ -0,0 +1,196 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/common/test_common.h"
#include "srsue/hdr/stack/rrc/rrc_cell.h"
#include "srsue/hdr/stack/rrc/rrc_rlf_report.h"
using namespace srsue;
int test_single()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas{};
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{1, 3400}, false);
rlf_report.set_failure(list, rrc_rlf_report::rlf);
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_single: %s\n", jw.to_string().c_str());
TESTASSERT(!out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.size() == 0);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 == 1);
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = 3400);
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::rlf);
return SRSRAN_SUCCESS;
}
int test_neighbours()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas{};
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.set_failure(list, rrc_rlf_report::hof);
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_neighbours: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.size() == 2);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[0].carrier_freq_r9 = 3400);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[0].meas_result_list_r9[0].pci == 1);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[1].carrier_freq_r9 = 3400);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[1].meas_result_list_r9[0].pci == 6);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 == 4);
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = 3400);
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int test_reest()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas{};
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.set_failure(list, rrc_rlf_report::hof);
rlf_report.set_reest_gci(list.serving_cell().get_cell_id_bit(), list.serving_cell().get_plmn_asn1(0));
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_reest: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(out.reest_cell_id_r10.is_present());
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int test_ho()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
rlf_report.init(&task_sched);
phy_meas_t pmeas{};
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.received_ho_command(list.serving_cell().get_cell_id_bit());
for (int i = 0; i < 1000; i++) {
task_sched.tic();
task_sched.run_pending_tasks();
}
rlf_report.set_failure(list, rrc_rlf_report::hof);
rlf_report.set_reest_gci(list.serving_cell().get_cell_id_bit(), list.serving_cell().get_plmn_asn1(0));
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_ho: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(out.reest_cell_id_r10.is_present());
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int main()
{
TESTASSERT(test_single() == SRSRAN_SUCCESS);
TESTASSERT(test_neighbours() == SRSRAN_SUCCESS);
TESTASSERT(test_reest() == SRSRAN_SUCCESS);
TESTASSERT(test_ho() == SRSRAN_SUCCESS);
printf("Success\n");
return SRSRAN_SUCCESS;
}

@ -20,10 +20,10 @@
*/
#include "srsran/common/bcd_helpers.h"
#include "srsran/common/test_common.h"
#include "srsran/common/tsan_options.h"
#include "srsran/interfaces/ue_pdcp_interfaces.h"
#include "srsran/srslog/srslog.h"
#include "srsran/support/srsran_test.h"
#include "srsran/test/ue_test_interfaces.h"
#include "srsue/hdr/stack/upper/gw.h"
#include "srsue/hdr/stack/upper/nas.h"

@ -19,7 +19,7 @@
*
*/
#include "srsran/common/test_common.h"
#include "srsran/support/srsran_test.h"
#include "srsue/hdr/stack/upper/usim.h"
using namespace srsue;

@ -37,6 +37,7 @@ public:
};
private:
srsran_rnti_type_t dl_rnti_type = srsran_rnti_type_c;
uint16_t rnti = 0;
bool valid = false;
uint32_t sr_period = 0;
@ -81,7 +82,7 @@ public:
}
}
int sf_indication(const uint32_t tti) override { return 0; }
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return {rnti, dl_rnti_type}; }
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override
{
@ -98,7 +99,11 @@ public:
action->tb.payload = tx_harq_proc[grant.pid].get_tb(grant.tbs);
action->tb.softbuffer = &tx_harq_proc[grant.pid].get_softbuffer(grant.ndi);
}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override
{
dl_rnti_type = srsran_rnti_type_ra;
rnti = 1 + s_id + 14 * t_id + 14 * 80 * f_id + 14 * 80 * 8 * ul_carrier_id;
}
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override
{
if (sr_period == 0) {

Loading…
Cancel
Save