diff --git a/lib/include/srsran/adt/bounded_bitset.h b/lib/include/srsran/adt/bounded_bitset.h index 7c3234802..1926e2130 100644 --- a/lib/include/srsran/adt/bounded_bitset.h +++ b/lib/include/srsran/adt/bounded_bitset.h @@ -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 #include #include diff --git a/lib/include/srsran/adt/bounded_vector.h b/lib/include/srsran/adt/bounded_vector.h index 417bf9d8d..c543445e6 100644 --- a/lib/include/srsran/adt/bounded_vector.h +++ b/lib/include/srsran/adt/bounded_vector.h @@ -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 #include #include diff --git a/lib/include/srsran/adt/circular_buffer.h b/lib/include/srsran/adt/circular_buffer.h index 55c7cee76..d92b865a4 100644 --- a/lib/include/srsran/adt/circular_buffer.h +++ b/lib/include/srsran/adt/circular_buffer.h @@ -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 #include diff --git a/lib/include/srsran/adt/circular_map.h b/lib/include/srsran/adt/circular_map.h index 9d9b26aee..069fc94e7 100644 --- a/lib/include/srsran/adt/circular_map.h +++ b/lib/include/srsran/adt/circular_map.h @@ -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 namespace srsran { diff --git a/lib/include/srsran/adt/expected.h b/lib/include/srsran/adt/expected.h index 81b7f3be3..16e1b9475 100644 --- a/lib/include/srsran/adt/expected.h +++ b/lib/include/srsran/adt/expected.h @@ -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 #include diff --git a/lib/include/srsran/adt/interval.h b/lib/include/srsran/adt/interval.h index def72095c..e09798a5c 100644 --- a/lib/include/srsran/adt/interval.h +++ b/lib/include/srsran/adt/interval.h @@ -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 #include #include diff --git a/lib/include/srsran/adt/move_callback.h b/lib/include/srsran/adt/move_callback.h index 8fdc10a2b..e61d212b8 100644 --- a/lib/include/srsran/adt/move_callback.h +++ b/lib/include/srsran/adt/move_callback.h @@ -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 #include #include @@ -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 {} diff --git a/lib/include/srsran/adt/optional.h b/lib/include/srsran/adt/optional.h index 9d3db2d6f..cbd1d59f0 100644 --- a/lib/include/srsran/adt/optional.h +++ b/lib/include/srsran/adt/optional.h @@ -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 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)); } diff --git a/lib/include/srsran/adt/optional_array.h b/lib/include/srsran/adt/optional_array.h new file mode 100644 index 000000000..edacb104c --- /dev/null +++ b/lib/include/srsran/adt/optional_array.h @@ -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 + +namespace srsran { + +namespace detail { + +template +class base_optional_span +{ + using base_t = base_optional_span; + using T = typename Vec::value_type::value_type; + +protected: + template + class iterator_impl + { + using It = iterator_impl; + + 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::max(); + }; + + size_t nof_elems = 0; + Vec vec; + +public: + using value_type = T; + using iterator = iterator_impl; + using const_iterator = iterator_impl; + + // 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 + 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); + } +}; + +template +class base_optional_vector : public base_optional_span +{ + using base_t = base_optional_span; + +public: + using value_type = typename base_optional_span::value_type; + using iterator = typename base_optional_span::iterator; + using const_iterator = typename base_optional_span::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 +class optional_array : public detail::base_optional_vector, N> > +{}; + +/** + * Contrarily to optional_array, this class may allocate and cause pointer/reference/iterator invalidation. + * However, the indexes will remain valid. + * @tparam T + */ +template +class optional_vector : public detail::base_optional_vector > > +{ + using base_t = detail::base_optional_vector > >; + +public: + /// May allocate and cause pointer invalidation + template + void insert(size_t idx, U&& u) + { + if (idx >= this->vec.size()) { + this->vec.resize(idx + 1); + } + base_t::insert(idx, std::forward(u)); + } +}; + +template +class optional_span : public detail::base_optional_span > > +{ + using base_t = detail::base_optional_span > >; + +public: + template + optional_span(const optional_array& ar) : base_t::vec(ar) + {} + optional_span(const optional_vector& ar) : base_t::vec(ar) {} +}; + +namespace detail { + +template +class base_split_optional_span +{ +protected: + using presence_type = typename std::conditional::value, const bool, bool>::type; + + T* ptr = nullptr; + presence_type* present_ptr = nullptr; + size_t len = 0; + + template + class iterator_impl + { + using It = iterator_impl; + using Parent = typename std:: + conditional::value, const base_split_optional_span, base_split_optional_span >::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::max(); + }; + +public: + using value_type = T; + using iterator = iterator_impl; + using const_iterator = iterator_impl; + + constexpr base_split_optional_span() = default; + template + 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 +class split_optional_span : public detail::base_split_optional_span +{ + using base_t = detail::base_split_optional_span; + +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 + 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); + } + 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 +class split_optional_span : public detail::base_split_optional_span +{ + using base_t = detail::base_split_optional_span; + 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 +split_optional_span +make_optional_span(T* array, + typename std::conditional::value, const bool, bool>::type* present, + size_t N) +{ + return split_optional_span(array, present, N); +} +template +split_optional_span + make_optional_span(T (&array)[N], + typename std::conditional::value, const bool, bool>::type (&present)[N]) +{ + return split_optional_span(array, present); +} + +} // namespace srsran + +#endif // SRSRAN_OPTIONAL_ARRAY_H diff --git a/lib/include/srsran/adt/pool/batch_mem_pool.h b/lib/include/srsran/adt/pool/batch_mem_pool.h index dbe7b327e..76add9095 100644 --- a/lib/include/srsran/adt/pool/batch_mem_pool.h +++ b/lib/include/srsran/adt/pool/batch_mem_pool.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 #include diff --git a/lib/include/srsran/adt/pool/linear_allocator.h b/lib/include/srsran/adt/pool/linear_allocator.h index 960a9edee..02088dfa5 100644 --- a/lib/include/srsran/adt/pool/linear_allocator.h +++ b/lib/include/srsran/adt/pool/linear_allocator.h @@ -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 { diff --git a/lib/include/srsran/asn1/asn1_utils.h b/lib/include/srsran/asn1/asn1_utils.h index 1d44f38cc..266cb56cc 100644 --- a/lib/include/srsran/asn1/asn1_utils.h +++ b/lib/include/srsran/asn1/asn1_utils.h @@ -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 #include #include diff --git a/lib/include/srsran/common/slot_point.h b/lib/include/srsran/common/slot_point.h index 3bf0ca35d..4d0f25433 100644 --- a/lib/include/srsran/common/slot_point.h +++ b/lib/include/srsran/common/slot_point.h @@ -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 { diff --git a/lib/include/srsran/common/test_common.h b/lib/include/srsran/common/test_common.h index 972ac5b8a..d4f75027b 100644 --- a/lib/include/srsran/common/test_common.h +++ b/lib/include/srsran/common/test_common.h @@ -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 @@ -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 - -#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 diff --git a/lib/include/srsran/common/tti_point.h b/lib/include/srsran/common/tti_point.h index a25729bc5..91f73d52e 100644 --- a/lib/include/srsran/common/tti_point.h +++ b/lib/include/srsran/common/tti_point.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 #include diff --git a/lib/include/srsran/interfaces/pdcp_interface_types.h b/lib/include/srsran/interfaces/pdcp_interface_types.h index 979959d5f..aea05b724 100644 --- a/lib/include/srsran/interfaces/pdcp_interface_types.h +++ b/lib/include/srsran/interfaces/pdcp_interface_types.h @@ -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 diff --git a/lib/include/srsran/phy/phch/dci_nr.h b/lib/include/srsran/phy/phch/dci_nr.h index de3396a31..0f6f83edf 100644 --- a/lib/include/srsran/phy/phch/dci_nr.h +++ b/lib/include/srsran/phy/phch/dci_nr.h @@ -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 diff --git a/lib/include/srsran/phy/phch/uci_cfg_nr.h b/lib/include/srsran/phy/phch/uci_cfg_nr.h index 5e062e8b9..12fb590da 100644 --- a/lib/include/srsran/phy/phch/uci_cfg_nr.h +++ b/lib/include/srsran/phy/phch/uci_cfg_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; diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index b95fdb07d..3f5743702 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -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 #include diff --git a/lib/include/srsran/common/srsran_assert.h b/lib/include/srsran/support/srsran_assert.h similarity index 59% rename from lib/include/srsran/common/srsran_assert.h rename to lib/include/srsran/support/srsran_assert.h index e22587a6c..3e27f1608 100644 --- a/lib/include/srsran/common/srsran_assert.h +++ b/lib/include/srsran/support/srsran_assert.h @@ -22,38 +22,54 @@ #ifndef SRSRAN_ASSERT_H #define SRSRAN_ASSERT_H +#ifdef __cplusplus #include "srsran/srslog/srslog.h" #include +#include #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 +#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 diff --git a/lib/include/srsran/support/srsran_test.h b/lib/include/srsran/support/srsran_test.h new file mode 100644 index 000000000..c247c69af --- /dev/null +++ b/lib/include/srsran/support/srsran_test.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 +[[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 +[[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 + +#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 diff --git a/lib/src/common/phy_cfg_nr_default.cc b/lib/src/common/phy_cfg_nr_default.cc index 6a429c113..e7e3ff74d 100644 --- a/lib/src/common/phy_cfg_nr_default.cc +++ b/lib/src/common/phy_cfg_nr_default.cc @@ -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) { diff --git a/lib/src/pdcp/pdcp.cc b/lib/src/pdcp/pdcp.cc index 28f7da522..2715f7959 100644 --- a/lib/src/pdcp/pdcp.cc +++ b/lib/src/pdcp/pdcp.cc @@ -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 entity; diff --git a/lib/src/pdcp/pdcp_entity_lte.cc b/lib/src/pdcp/pdcp_entity_lte.cc index 73b0a583e..503bc1cc1 100644 --- a/lib/src/pdcp/pdcp_entity_lte.cc +++ b/lib/src/pdcp/pdcp_entity_lte.cc @@ -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; diff --git a/lib/src/pdcp/pdcp_entity_nr.cc b/lib/src/pdcp/pdcp_entity_nr.cc index 8c9c12c76..477f4c05d 100644 --- a/lib/src/pdcp/pdcp_entity_nr.cc +++ b/lib/src/pdcp/pdcp_entity_nr.cc @@ -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); diff --git a/lib/src/phy/ch_estimation/test/chest_test_srs.c b/lib/src/phy/ch_estimation/test/chest_test_srs.c index c7c75010f..def116551 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_srs.c +++ b/lib/src/phy/ch_estimation/test/chest_test_srs.c @@ -19,8 +19,8 @@ * */ -#include "srsran/common/test_common.h" #include "srsran/srsran.h" +#include "srsran/support/srsran_test.h" #include #include #include diff --git a/lib/src/phy/ch_estimation/test/csi_rs_pattern_test.c b/lib/src/phy/ch_estimation/test/csi_rs_pattern_test.c index 04f8ed6b6..700267902 100644 --- a/lib/src/phy/ch_estimation/test/csi_rs_pattern_test.c +++ b/lib/src/phy/ch_estimation/test/csi_rs_pattern_test.c @@ -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 = {}; diff --git a/lib/src/phy/ch_estimation/test/csi_rs_test.c b/lib/src/phy/ch_estimation/test/csi_rs_test.c index 2815fe5d6..22fe89f60 100644 --- a/lib/src/phy/ch_estimation/test/csi_rs_test.c +++ b/lib/src/phy/ch_estimation/test/csi_rs_test.c @@ -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 #include #include diff --git a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c index 0231b1655..3598b5efd 100644 --- a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c +++ b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c @@ -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 #include #include diff --git a/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c b/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c index 9585d1be9..7d6731971 100644 --- a/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c +++ b/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c @@ -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 #include #include diff --git a/lib/src/phy/fec/block/test/block_test.c b/lib/src/phy/fec/block/test/block_test.c index e896fe31e..955dca84e 100644 --- a/lib/src/phy/fec/block/test/block_test.c +++ b/lib/src/phy/fec/block/test/block_test.c @@ -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 #include #include diff --git a/lib/src/phy/fec/polar/test/polar_interleaver_test.c b/lib/src/phy/fec/polar/test/polar_interleaver_test.c index eb11096af..5e807b838 100644 --- a/lib/src/phy/fec/polar/test/polar_interleaver_test.c +++ b/lib/src/phy/fec/polar/test/polar_interleaver_test.c @@ -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) { diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c index 786c81164..df873da6a 100644 --- a/lib/src/phy/phch/dci_nr.c +++ b/lib/src/phy/phch/dci_nr.c @@ -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); diff --git a/lib/src/phy/phch/test/dci_nr_test.c b/lib/src/phy/phch/test/dci_nr_test.c index 6e9199939..81ae6aa58 100644 --- a/lib/src/phy/phch/test/dci_nr_test.c +++ b/lib/src/phy/phch/test/dci_nr_test.c @@ -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 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 = {}; diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index 94d8d94d5..b7f83bde3 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -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"); diff --git a/lib/src/phy/utils/test/re_pattern_test.c b/lib/src/phy/utils/test/re_pattern_test.c index bb077508b..8c3e58c3c 100644 --- a/lib/src/phy/utils/test/re_pattern_test.c +++ b/lib/src/phy/utils/test/re_pattern_test.c @@ -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) { diff --git a/lib/src/phy/utils/test/ring_buffer_test.c b/lib/src/phy/utils/test/ring_buffer_test.c index c56d8eeea..9cf30fd51 100644 --- a/lib/src/phy/utils/test/ring_buffer_test.c +++ b/lib/src/phy/utils/test/ring_buffer_test.c @@ -19,7 +19,7 @@ * */ -#include "srsran/common/test_common.h" +#include "srsran/support/srsran_test.h" #include #include #include diff --git a/lib/test/adt/CMakeLists.txt b/lib/test/adt/CMakeLists.txt index ffa479e09..8dc1a0d1f 100644 --- a/lib/test/adt/CMakeLists.txt +++ b/lib/test/adt/CMakeLists.txt @@ -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) diff --git a/lib/test/adt/bounded_vector_test.cc b/lib/test/adt/bounded_vector_test.cc index c58211d87..68d547b5d 100644 --- a/lib/test/adt/bounded_vector_test.cc +++ b/lib/test/adt/bounded_vector_test.cc @@ -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 a; @@ -97,11 +97,9 @@ int test_ctor() bounded_vector 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 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 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; } \ No newline at end of file diff --git a/lib/test/adt/optional_array_test.cc b/lib/test/adt/optional_array_test.cc new file mode 100644 index 000000000..7ddf21625 --- /dev/null +++ b/lib/test/adt/optional_array_test.cc @@ -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 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 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 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; +} diff --git a/lib/test/common/timer_test.cc b/lib/test/common/timer_test.cc index f420f0749..2854acfb8 100644 --- a/lib/test/common/timer_test.cc +++ b/lib/test/common/timer_test.cc @@ -19,8 +19,8 @@ * */ -#include "srsran/common/test_common.h" #include "srsran/common/timers.h" +#include "srsran/support/srsran_test.h" #include #include #include @@ -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; } diff --git a/lib/test/common/tti_point_test.cc b/lib/test/common/tti_point_test.cc index 16162c0e5..cd376f7aa 100644 --- a/lib/test/common/tti_point_test.cc +++ b/lib/test/common/tti_point_test.cc @@ -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() diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_cell.h b/srsenb/hdr/stack/mac/nr/sched_nr_cell.h index b3d810a19..71425d6e5 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_cell.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_cell.h @@ -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 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 { diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h b/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h index afc6b473a..d85f49036 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h @@ -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 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; diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_grant_allocator.h b/srsenb/hdr/stack/mac/nr/sched_nr_grant_allocator.h index 017ecbde8..0d20d729a 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_grant_allocator.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_grant_allocator.h @@ -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, diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_interface.h b/srsenb/hdr/stack/mac/nr/sched_nr_interface.h index 8b06d50a1..e642c66b4 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_interface.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_interface.h @@ -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 bwps{1}; // idx0 for BWP-common }; diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sched_phy_resource.h b/srsenb/hdr/stack/mac/sched_phy_ch/sched_phy_resource.h index eb3ca3875..b0330ac03 100644 --- a/srsenb/hdr/stack/mac/sched_phy_ch/sched_phy_resource.h +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sched_phy_resource.h @@ -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; } diff --git a/srsenb/src/stack/mac/nr/sched_nr_cell.cc b/srsenb/src/stack/mac/nr/sched_nr_cell.cc index 0497e7386..2ff51c7d6 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_cell.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_cell.cc @@ -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); diff --git a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc index 037a54c69..bac130f1c 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc @@ -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); } } } diff --git a/srsenb/src/stack/mac/nr/sched_nr_grant_allocator.cc b/srsenb/src/stack/mac/nr/sched_nr_grant_allocator.cc index 8f675a61a..34e8c0815 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_grant_allocator.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_grant_allocator.cc @@ -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; } diff --git a/srsenb/src/stack/mac/nr/sched_nr_helpers.cc b/srsenb/src/stack/mac/nr/sched_nr_helpers.cc index 8eef03757..3cab3c4e8 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_helpers.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_helpers.cc @@ -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; } diff --git a/srsenb/src/stack/mac/nr/sched_nr_worker.cc b/srsenb/src/stack/mac/nr/sched_nr_worker.cc index e5fdbb09d..2736a9051 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_worker.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_worker.cc @@ -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"); } diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 40383c656..cea10ea15 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -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(rrc_event_type::con_reconf), + static_cast(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) { diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 0411c812e..5c215a35f 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -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) { diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 023f2d98a..08cd8486c 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -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); diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index 830f5f532..76b7de279 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -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 #include diff --git a/srsenb/test/mac/sched_dci_test.cc b/srsenb/test/mac/sched_dci_test.cc index 45ee5d93a..44f74410a 100644 --- a/srsenb/test/mac/sched_dci_test.cc +++ b/srsenb/test/mac/sched_dci_test.cc @@ -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 diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index 5c30a957c..33b1f5559 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -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 = diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index eac1412f9..6da9fccb5 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -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 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); diff --git a/srsue/hdr/stack/rrc/rrc_cell.h b/srsue/hdr/stack/rrc/rrc_cell.h index d01a6b00f..33389cfee 100644 --- a/srsue/hdr/stack/rrc/rrc_cell.h +++ b/srsue/hdr/stack/rrc/rrc_cell.h @@ -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; } diff --git a/srsue/hdr/stack/rrc/rrc_common.h b/srsue/hdr/stack/rrc/rrc_common.h index 3eba201e0..028b5650a 100644 --- a/srsue/hdr/stack/rrc/rrc_common.h +++ b/srsue/hdr/stack/rrc/rrc_common.h @@ -24,6 +24,8 @@ namespace srsue { +#include + // 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 diff --git a/srsue/hdr/stack/rrc/rrc_meas.h b/srsue/hdr/stack/rrc/rrc_meas.h index 71e0d1144..b5bde4cdf 100644 --- a/srsue/hdr/stack/rrc/rrc_meas.h +++ b/srsue/hdr/stack/rrc/rrc_meas.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); diff --git a/srsue/hdr/stack/rrc/rrc_rlf_report.h b/srsue/hdr/stack/rrc/rrc_rlf_report.h new file mode 100644 index 000000000..85948c931 --- /dev/null +++ b/srsue/hdr/stack/rrc/rrc_rlf_report.h @@ -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_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_ diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 843043d1a..4c7c54555 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -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"); } diff --git a/srsue/src/stack/mac/test/mac_test.cc b/srsue/src/stack/mac/test/mac_test.cc index 4fe055fd0..7cd4894bd 100644 --- a/srsue/src/stack/mac/test/mac_test.cc +++ b/srsue/src/stack/mac/test/mac_test.cc @@ -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" diff --git a/srsue/src/stack/rrc/CMakeLists.txt b/srsue/src/stack/rrc/CMakeLists.txt index b6be724a3..7d83545e8 100644 --- a/srsue/src/stack/rrc/CMakeLists.txt +++ b/srsue/src/stack/rrc/CMakeLists.txt @@ -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) diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 1f34fa851..949442843 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.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); +} + /******************************************************************************* * * diff --git a/srsue/src/stack/rrc/rrc_cell.cc b/srsue/src/stack/rrc/rrc_cell.cc index 66e5ffbdb..ef501f6cc 100644 --- a/srsue/src/stack/rrc/rrc_cell.cc +++ b/srsue/src/stack/rrc/rrc_cell.cc @@ -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_; diff --git a/srsue/src/stack/rrc/rrc_common.cc b/srsue/src/stack/rrc/rrc_common.cc new file mode 100644 index 000000000..9c1f5a8bb --- /dev/null +++ b/srsue/src/stack/rrc/rrc_common.cc @@ -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 \ No newline at end of file diff --git a/srsue/src/stack/rrc/rrc_meas.cc b/srsue/src/stack/rrc/rrc_meas.cc index b1d214ce1..9d6f3ae34 100644 --- a/srsue/src/stack/rrc/rrc_meas.cc +++ b/srsue/src/stack/rrc/rrc_meas.cc @@ -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); } } diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 9a754176c..677c4aefc 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -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); diff --git a/srsue/src/stack/rrc/rrc_rlf_report.cc b/srsue/src/stack/rrc/rrc_rlf_report.cc new file mode 100644 index 000000000..c4930af9c --- /dev/null +++ b/srsue/src/stack/rrc/rrc_rlf_report.cc @@ -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_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 \ No newline at end of file diff --git a/srsue/src/stack/rrc/test/CMakeLists.txt b/srsue/src/stack/rrc/test/CMakeLists.txt index e77ef9d0d..7567f75a9 100644 --- a/srsue/src/stack/rrc/test/CMakeLists.txt +++ b/srsue/src/stack/rrc/test/CMakeLists.txt @@ -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) diff --git a/srsue/src/stack/rrc/test/rrc_rlf_report_test.cc b/srsue/src/stack/rrc/test/rrc_rlf_report_test.cc new file mode 100644 index 000000000..3d6b76689 --- /dev/null +++ b/srsue/src/stack/rrc/test/rrc_rlf_report_test.cc @@ -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 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 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 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 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; +} diff --git a/srsue/src/stack/upper/test/nas_test.cc b/srsue/src/stack/upper/test/nas_test.cc index d850256da..c3d418670 100644 --- a/srsue/src/stack/upper/test/nas_test.cc +++ b/srsue/src/stack/upper/test/nas_test.cc @@ -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" diff --git a/srsue/src/stack/upper/test/usim_test.cc b/srsue/src/stack/upper/test/usim_test.cc index 879db81e9..32f9e3f5d 100644 --- a/srsue/src/stack/upper/test/usim_test.cc +++ b/srsue/src/stack/upper/test/usim_test.cc @@ -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; diff --git a/test/phy/dummy_ue_stack.h b/test/phy/dummy_ue_stack.h index 186ecc413..0610dd6f4 100644 --- a/test/phy/dummy_ue_stack.h +++ b/test/phy/dummy_ue_stack.h @@ -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) {