new wrapper-based design for stack procedures. Removes extra base class, gets rid of spurious copies/moves during the pop(), and allows the use of a non-default ctor()

master
Francisco Paisana 5 years ago committed by Andre Puschmann
parent 3828e03f33
commit c1be118d1d

@ -33,7 +33,34 @@ enum class proc_state_t { on_going, success, error, inactive };
enum class proc_outcome_t { repeat, yield, success, error }; enum class proc_outcome_t { repeat, yield, success, error };
/************************************************************************************** /**************************************************************************************
* class: proc_impl_t * helper functions for overloading
************************************************************************************/
namespace detail {
template <class T>
auto optional_stop(T* obj, int is_success) -> decltype(obj->stop())
{
obj->stop(is_success);
}
inline auto optional_stop(...) -> void
{
// do nothing
}
template <class T>
auto optional_clear(T* obj) -> decltype(obj->clear())
{
obj->clear();
}
inline auto optional_clear(...) -> void
{
// do nothing
}
} // namespace detail
/**************************************************************************************
* class: proc_itf_t
* Provides an polymorphic interface for resumable procedures. This base can then be used * Provides an polymorphic interface for resumable procedures. This base can then be used
* by a task dispatch queue via the method "run()". * by a task dispatch queue via the method "run()".
* Every procedure starts in inactive state, and finishes with success or error. * Every procedure starts in inactive state, and finishes with success or error.
@ -52,54 +79,25 @@ enum class proc_outcome_t { repeat, yield, success, error };
* upon procedure completion, like sending back a response. * upon procedure completion, like sending back a response.
* - set_proc_state() / is_#() - setter and getters for current procedure state * - set_proc_state() / is_#() - setter and getters for current procedure state
************************************************************************************/ ************************************************************************************/
class proc_impl_t class proc_manager_itf_t
{ {
public: public:
proc_impl_t() : proc_state(proc_state_t::inactive) {} virtual bool run() = 0;
virtual ~proc_impl_t() = default; virtual ~proc_manager_itf_t() = default;
virtual proc_outcome_t step() = 0;
virtual void stop() {} // may be overloaded
bool run()
{
proc_outcome_t outcome = proc_outcome_t::repeat;
while (is_running() and outcome == proc_outcome_t::repeat) {
outcome = step();
if (outcome == proc_outcome_t::error) {
set_proc_state(proc_state_t::error);
} else if (outcome == proc_outcome_t::success) {
set_proc_state(proc_state_t::success);
}
}
return is_running();
}
void set_proc_state(proc_state_t new_state)
{
proc_state = new_state;
if (proc_state == proc_state_t::error or proc_state == proc_state_t::success) {
stop();
}
}
bool is_error() const { return proc_state == proc_state_t::error; }
bool is_success() const { return proc_state == proc_state_t::success; }
bool is_running() const { return proc_state == proc_state_t::on_going; }
bool is_complete() const { return is_success() or is_error(); }
bool is_active() const { return proc_state != proc_state_t::inactive; }
private:
proc_state_t proc_state;
}; };
template <typename T>
struct proc_result_t;
/************************************************************************************** /**************************************************************************************
* class: proc_t<T> * class: proc_manager_t<T>
* Handles the lifetime, of a procedure T that derives from proc_impl_t, including * Manages the lifetime, of a procedure T, including its alloc, launching,
* its alloc, initialization, and reset back to initial state once the procedure has been * and reset back to initial, uninit state once the procedure has been
* completed and the user has extracted its results. * completed and the user has extracted its results.
* Can only be re-launched when a procedure T becomes inactive. * Can only be re-launched when a procedure T becomes inactive.
* It uses a unique_ptr<T> to allow the use of procedures that are forward declared. * It uses a unique_ptr<T> to allow the use of procedures that are forward declared.
* It provides the following methods: * It provides the following methods:
* - run() - calls proc_impl_t::run(). See above. * - run() - calls T::step() and update the procedure state
* - launch() - initializes the procedure T by calling T::init(...). Handles the case * - launch() - initializes the procedure T by calling T::init(...). Handles the case
* of failed initialization, and forbids the initialization of procedures * of failed initialization, and forbids the initialization of procedures
* that are already active. * that are already active.
@ -110,43 +108,43 @@ private:
* specifying how each event type should be handled. * specifying how each event type should be handled.
************************************************************************************/ ************************************************************************************/
template <class T> template <class T>
class proc_t class proc_t final : public proc_manager_itf_t
{ {
public: public:
explicit proc_t() : proc_impl_ptr(new T()) {} template <typename... Args>
T* get() { return proc_impl_ptr.get(); } explicit proc_t(Args&&... args) : proc_impl_ptr(new T(std::forward<Args>(args)...))
bool is_active() const { return proc_impl_ptr->is_active(); }
bool is_complete() const { return proc_impl_ptr->is_complete(); }
T* release() { return proc_impl_ptr.release(); }
bool run() { return proc_impl_ptr->run(); }
void clear()
{ {
// Destructs the current object, and calls default ctor (which sets proc back to inactive and ready for another run)
proc_impl_ptr->~T();
new (proc_impl_ptr.get()) T();
} }
template <class Event> bool run() override
void trigger_event(Event&& e)
{ {
if (proc_impl_ptr->is_running()) { proc_outcome_t outcome = proc_outcome_t::repeat;
proc_outcome_t outcome = proc_impl_ptr->trigger_event(std::forward<Event>(e)); while (is_running() and outcome == proc_outcome_t::repeat) {
if (outcome == proc_outcome_t::error) { outcome = proc_impl_ptr->step();
proc_impl_ptr->set_proc_state(proc_state_t::error); handle_outcome(outcome);
} else if (outcome == proc_outcome_t::success) {
proc_impl_ptr->set_proc_state(proc_state_t::success);
} }
return is_running();
} }
void clear()
{
// resets procedure and sets proc_t back to inactive
detail::optional_clear(proc_impl_ptr.get());
proc_state = proc_state_t::inactive;
} }
T pop() const T* get() const { return proc_impl_ptr.get(); }
bool is_active() const { return proc_state != proc_state_t::inactive; }
bool is_complete() const { return proc_state == proc_state_t::success or proc_state == proc_state_t::error; }
T* release() { return proc_impl_ptr.release(); }
template <class Event>
void trigger_event(Event&& e)
{ {
if (not proc_impl_ptr->is_complete()) { if (is_running()) {
return T(); proc_outcome_t outcome = proc_impl_ptr->trigger_event(std::forward<Event>(e));
handle_outcome(outcome);
} }
T ret(std::move(*proc_impl_ptr));
clear();
return ret;
} }
template <class... Args> template <class... Args>
@ -156,15 +154,16 @@ public:
// if already active // if already active
return false; return false;
} }
proc_impl_ptr->set_proc_state(proc_state_t::on_going); proc_state = proc_state_t::on_going;
proc_outcome_t init_ret = proc_impl_ptr->init(std::forward<Args>(args)...); proc_outcome_t init_ret = proc_impl_ptr->init(std::forward<Args>(args)...);
switch (init_ret) { switch (init_ret) {
case proc_outcome_t::error: case proc_outcome_t::error:
proc_impl_ptr->set_proc_state(proc_state_t::error); // call stop as an error handle_outcome(init_ret);
clear(); clear();
return false; return false;
case proc_outcome_t::success: case proc_outcome_t::success:
proc_impl_ptr->set_proc_state(proc_state_t::success); handle_outcome(init_ret);
// does not reset, and returns true
break; break;
case proc_outcome_t::repeat: case proc_outcome_t::repeat:
run(); // call run right away run(); // call run right away
@ -175,41 +174,85 @@ public:
return true; return true;
} }
private: proc_result_t<T> pop();
protected:
friend proc_result_t<T>;
bool is_running() const { return proc_state == proc_state_t::on_going; }
void handle_outcome(proc_outcome_t outcome)
{
switch (outcome) {
case proc_outcome_t::error:
proc_state = proc_state_t::error;
detail::optional_stop(proc_impl_ptr.get(), false);
break;
case proc_outcome_t::success:
proc_state = proc_state_t::success;
detail::optional_stop(proc_impl_ptr.get(), true);
break;
case proc_outcome_t::repeat:
run();
break;
default:
break;
}
}
proc_state_t proc_state = proc_state_t::inactive;
std::unique_ptr<T> proc_impl_ptr; std::unique_ptr<T> proc_impl_ptr;
}; };
template <typename T>
struct proc_result_t {
explicit proc_result_t(proc_t<T>* parent_) : parent(parent_) {}
~proc_result_t()
{
if (parent->is_complete()) {
parent->clear();
}
}
const T* proc() const { return parent->is_complete() ? parent->proc_impl_ptr.get() : nullptr; }
bool is_success() const { return parent->proc_state == proc_state_t::success; }
bool is_error() const { return parent->proc_state == proc_state_t::error; }
bool is_complete() const { return parent->is_complete(); }
private:
proc_t<T>* parent;
};
template <typename T>
proc_result_t<T> proc_t<T>::pop()
{
return proc_result_t<T>{this};
}
/************************************************************************************** /**************************************************************************************
* class: func_proc_t * class: func_proc_t
* A proc_impl_t used to store lambda functions and other function pointers as a step() * A proc used to store lambda functions and other function pointers as a step()
* method, avoiding this way, always having to create a new class per procedure. * method, avoiding this way, always having to create a new class per procedure.
************************************************************************************/ ************************************************************************************/
class func_proc_t : public proc_impl_t class func_proc_t
{ {
public: public:
proc_outcome_t init(std::function<proc_outcome_t()> step_func_) explicit func_proc_t(std::function<proc_outcome_t()> step_func_) : step_func(std::move(step_func_)) {}
{ proc_outcome_t init() { return proc_outcome_t::yield; }
step_func = std::move(step_func_); proc_outcome_t step() { return step_func(); }
return proc_outcome_t::yield;
}
proc_outcome_t step() final { return step_func(); }
private: private:
std::function<proc_outcome_t()> step_func; std::function<proc_outcome_t()> step_func;
}; };
/************************************************************************************** /**************************************************************************************
* class: func_proc_t * class: query_proc_t
* A helper proc_impl_t whose step()/stop() are no op, but has a trigger_event() that * A helper proc_impl_t whose step()/stop() are no op, but has a trigger_event() that
* signals that the method has finished and store a result of type OutcomeType. * signals that the method has finished and store a result of type OutcomeType.
************************************************************************************/ ************************************************************************************/
template <class OutcomeType> template <class OutcomeType>
class query_proc_t : public proc_impl_t class query_proc_t
{ {
public: public:
proc_outcome_t init() { return proc_outcome_t::yield; } proc_outcome_t init() { return proc_outcome_t::yield; }
proc_outcome_t step() final { return proc_outcome_t::yield; } proc_outcome_t step() { return proc_outcome_t::yield; }
proc_outcome_t trigger_event(const OutcomeType& outcome_) proc_outcome_t trigger_event(const OutcomeType& outcome_)
{ {
@ -224,15 +267,16 @@ private:
}; };
/************************************************************************************** /**************************************************************************************
* class: callback_list_t * class: proc_manager_list_t
* Stores procedures that derive from proc_impl_t. Its run() method calls sequentially * Stores procedure managers and, when run() is called, calls sequentially all
* all the stored procedures run() method, and removes the procedures if they have * the stored procedures run() method, and removes the procedures if they have
* completed. * completed.
* There are different ways to add a procedure to the list: * There are different ways to add a procedure to the list:
* - add_proc(...) - adds a proc_t<T>, and once the procedure has completed, takes it * - add_proc(...) - adds a proc_t<T>, and once the procedure has completed, takes it
* out of the container without resetting it back to its initial state * out of the container without resetting it back to its initial state
* or deleting. This is useful, if the user wants to extract the * or deleting. This is useful, if the user wants to extract the
* procedure result via proc_t<T>::pop() * procedure result after it has been taken off the manager list.
* "proc" variable has to outlive its completion
* - consume_proc(...) - receives a proc_t<T> as a rvalue, and calls the proc_t<T> * - consume_proc(...) - receives a proc_t<T> as a rvalue, and calls the proc_t<T>
* destructor once the procedure has ended. Useful, for procedures * destructor once the procedure has ended. Useful, for procedures
* for which the user is not interested in the result, or reusing * for which the user is not interested in the result, or reusing
@ -242,31 +286,32 @@ private:
* - defer_task(...) - same as consume_proc(...) but takes a function pointer that * - defer_task(...) - same as consume_proc(...) but takes a function pointer that
* specifies a proc_impl_t step() function * specifies a proc_impl_t step() function
************************************************************************************/ ************************************************************************************/
class callback_list_t class proc_manager_list_t
{ {
public: using proc_deleter_t = std::function<void(proc_manager_itf_t*)>;
typedef std::function<void(proc_impl_t*)> proc_deleter_t; using proc_obj_t = std::unique_ptr<proc_manager_itf_t, proc_deleter_t>;
typedef std::unique_ptr<proc_impl_t, proc_deleter_t> callback_obj_t;
template <class T> template <typename T>
struct recycle_deleter_t { struct recycle_deleter_t {
void operator()(proc_impl_t* p) void operator()(proc_manager_itf_t* p)
{ {
if (p != nullptr) { if (p != nullptr) {
T* Tp = static_cast<T*>(p); T* Tp = static_cast<T*>(p);
Tp->~T(); Tp->clear();
new (Tp) T(); // just resets back to inactive, and does not dealloc
} }
} }
}; };
template <class T> public:
template <typename T>
void add_proc(proc_t<T>& proc) void add_proc(proc_t<T>& proc)
{ {
if (proc.is_complete()) { if (proc.is_complete()) {
return; return;
} }
callback_obj_t ptr(proc.get(), [](proc_impl_t* p) { /* do nothing */ }); proc_obj_t ptr(&proc, [](proc_manager_itf_t* p) { /* do nothing */ });
callbacks.push_back(std::move(ptr)); proc_list.push_back(std::move(ptr));
} }
template <class T> template <class T>
@ -275,25 +320,25 @@ public:
if (proc.is_complete()) { if (proc.is_complete()) {
return; return;
} }
callback_obj_t ptr(proc.release(), std::default_delete<proc_impl_t>()); proc_obj_t ptr(new proc_t<T>(std::move(proc)), std::default_delete<proc_manager_itf_t>());
callbacks.push_back(std::move(ptr)); proc_list.push_back(std::move(ptr));
} }
template <class T> template <typename T>
void defer_proc(proc_t<T>& proc) void defer_proc(proc_t<T>& proc)
{ {
if (proc.is_complete()) { if (proc.is_complete()) {
proc.pop(); proc.clear();
return; return;
} }
callback_obj_t ptr(proc.get(), recycle_deleter_t<T>()); proc_obj_t ptr(&proc, recycle_deleter_t<proc_t<T> >());
callbacks.push_back(std::move(ptr)); proc_list.push_back(std::move(ptr));
} }
bool defer_task(std::function<proc_outcome_t()> step_func) bool defer_task(std::function<proc_outcome_t()> step_func)
{ {
proc_t<func_proc_t> proc; proc_t<func_proc_t> proc(std::move(step_func));
if (not proc.launch(std::move(step_func))) { if (not proc.launch()) {
return false; return false;
} }
consume_proc(std::move(proc)); consume_proc(std::move(proc));
@ -303,13 +348,13 @@ public:
void run() void run()
{ {
// Calls run for all callbacks. Remove the ones that have finished. The proc dtor is called. // Calls run for all callbacks. Remove the ones that have finished. The proc dtor is called.
callbacks.remove_if([](callback_obj_t& elem) { return not elem->run(); }); proc_list.remove_if([](proc_obj_t& elem) { return not elem->run(); });
} }
size_t size() const { return callbacks.size(); } size_t size() const { return proc_list.size(); }
private: private:
std::list<callback_obj_t> callbacks; std::list<proc_obj_t> proc_list;
}; };
} // namespace srslte } // namespace srslte

@ -70,6 +70,7 @@ target_link_libraries(mac_nr_pdu_test srslte_phy srslte_common ${CMAKE_THREAD_LI
add_test(mac_nr_pdu_test mac_nr_pdu_test) add_test(mac_nr_pdu_test mac_nr_pdu_test)
add_executable(stack_procedure_test stack_procedure_test.cc) add_executable(stack_procedure_test stack_procedure_test.cc)
add_test(stack_procedure_test stack_procedure_test)
add_executable(queue_test queue_test.cc) add_executable(queue_test queue_test.cc)
target_link_libraries(queue_test srslte_common ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(queue_test srslte_common ${CMAKE_THREAD_LIBS_INIT})

@ -121,9 +121,11 @@ void new_test()
TestObj::dtor_counter = 0; TestObj::dtor_counter = 0;
} }
class custom_proc : public srslte::proc_impl_t class custom_proc
{ {
public: public:
custom_proc() : ctor_value(5) {}
proc_outcome_t init(int a_) proc_outcome_t init(int a_)
{ {
if (a_ < 0) { if (a_ < 0) {
@ -131,19 +133,27 @@ public:
return proc_outcome_t::error; return proc_outcome_t::error;
} }
obj.id = a_; obj.id = a_;
reset_called = false;
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
proc_outcome_t step() final proc_outcome_t step()
{ {
if (counter++ > 5) { if (counter++ > 5) {
return proc_outcome_t::success; return proc_outcome_t::success;
} }
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
void stop() final { printf("TestObj %d stop() was called\n", obj.id); } void stop(bool is_success) { printf("TestObj %d stop() was called\n", obj.id); }
const char* name() const { return "custom proc"; } const char* name() const { return "custom proc"; }
void clear()
{
reset_called = true;
printf("TestObj was reset\n");
}
TestObj obj; TestObj obj;
const int ctor_value = 5;
bool reset_called = false;
private: private:
int counter = 0; int counter = 0;
@ -159,6 +169,7 @@ int test_local_1()
proc.launch(1); proc.launch(1);
TESTASSERT(proc.is_active()); TESTASSERT(proc.is_active());
TESTASSERT(not proc.is_complete()); TESTASSERT(not proc.is_complete());
TESTASSERT(not proc.get()->reset_called);
while (proc.run()) { while (proc.run()) {
} }
@ -166,29 +177,36 @@ int test_local_1()
TESTASSERT(proc.is_active()); TESTASSERT(proc.is_active());
TESTASSERT(proc.is_complete()); TESTASSERT(proc.is_complete());
printf("pop being called\n"); const custom_proc& procobj = *proc.get();
custom_proc procobj = proc.pop();
TESTASSERT(procobj.obj.id == 1); TESTASSERT(procobj.obj.id == 1);
TESTASSERT(procobj.is_success()); TESTASSERT(proc.is_active());
printf("clear() being called\n");
proc.clear();
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
TESTASSERT(proc.get()->obj.id == 0); // Proc is ready to be reused TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused
TESTASSERT(proc.get()->ctor_value == 5);
printf("EXIT\n"); printf("EXIT\n");
TESTASSERT(TestObj::copy_counter == 0); TESTASSERT(TestObj::copy_counter == 0);
TESTASSERT(TestObj::move_counter == 2); // pop() makes a swap which causes 2 moves TESTASSERT(TestObj::move_counter == 0);
TESTASSERT(TestObj::dtor_counter == 2); // 2 dtors inside pop() (handler and popped obj not yet destructed) TESTASSERT(TestObj::dtor_counter == 0); // destructor not called yet
return 0; return 0;
} }
int test_callback_1() int test_callback_1()
{ {
/*
* Description: Test a procedure inserted in a manager list via "proc_manager_list_t::add_proc(...)"
* - check if the proc is not cleared automatically after it finished (need to check the result)
* - check if pop() works as expected, and resets proc after proc_result_t<T> goes out of scope
*/
new_test(); new_test();
printf("\n--- Test %s ---\n", __func__); printf("\n--- Test %s ---\n", __func__);
srslte::callback_list_t callbacks; srslte::proc_manager_list_t callbacks;
srslte::proc_t<custom_proc> proc; srslte::proc_t<custom_proc> proc;
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
proc.launch(2); TESTASSERT(proc.launch(2));
callbacks.add_proc(proc); // We have to call pop() explicitly to take the result callbacks.add_proc(proc); // We have to call pop() explicitly to take the result
TESTASSERT(callbacks.size() == 1); TESTASSERT(callbacks.size() == 1);
@ -200,29 +218,38 @@ int test_callback_1()
TESTASSERT(proc.is_active()); TESTASSERT(proc.is_active());
TESTASSERT(proc.is_complete()); TESTASSERT(proc.is_complete());
TESTASSERT(proc.get()->obj.id == 2);
TESTASSERT(proc.is_active());
{
printf("pop being called\n"); printf("pop being called\n");
custom_proc procobj = proc.pop(); srslte::proc_result_t<custom_proc> ret = proc.pop();
TESTASSERT(procobj.is_success()); TESTASSERT(proc.is_active());
TESTASSERT(procobj.obj.id == 2); TESTASSERT(ret.is_success());
// proc::reset() is finally called
}
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused
TESTASSERT(proc.get()->obj.id == 0); // Proc is ready to be reused
printf("EXIT\n"); printf("EXIT\n");
TESTASSERT(TestObj::copy_counter == 0); TESTASSERT(TestObj::copy_counter == 0);
TESTASSERT(TestObj::move_counter == 2); // pop makes two moves TESTASSERT(TestObj::move_counter == 0);
TESTASSERT(TestObj::dtor_counter == 2); // handler not yet destructed TESTASSERT(TestObj::dtor_counter == 0); // handler not yet destructed
return 0; return 0;
} }
int test_callback_2() int test_callback_2()
{ {
/*
* Description: Test a procedure inserted in a manager list via "proc_manager_list_t::consume_proc(...)"
* - check if the proc disappears automatically after it finished
*/
new_test(); new_test();
printf("\n--- Test %s ---\n", __func__); printf("\n--- Test %s ---\n", __func__);
srslte::callback_list_t callbacks; srslte::proc_manager_list_t callbacks;
srslte::proc_t<custom_proc> proc; srslte::proc_t<custom_proc> proc;
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
proc.launch(3); TESTASSERT(proc.launch(3));
TESTASSERT(proc.is_active()); TESTASSERT(proc.is_active());
TESTASSERT(not proc.is_complete()); TESTASSERT(not proc.is_complete());
callbacks.consume_proc(std::move(proc)); callbacks.consume_proc(std::move(proc));
@ -235,16 +262,20 @@ int test_callback_2()
printf("EXIT\n"); printf("EXIT\n");
TESTASSERT(TestObj::copy_counter == 0); TESTASSERT(TestObj::copy_counter == 0);
TESTASSERT(TestObj::move_counter == 0); // no pop() TESTASSERT(TestObj::move_counter == 0); // it does not move proc itself, but its pointer
TESTASSERT(TestObj::dtor_counter == 1); // handler not yet destructed TESTASSERT(TestObj::dtor_counter == 1); // handler not yet destructed, but we called proc move
return 0; return 0;
} }
int test_callback_3() int test_callback_3()
{ {
/*
* Description: Test a procedure inserted in a manager list via "proc_manager_list_t::defer_proc(...)"
* - check if the proc is cleared automatically after it finished
*/
new_test(); new_test();
printf("\n--- Test %s ---\n", __func__); printf("\n--- Test %s ---\n", __func__);
srslte::callback_list_t callbacks; srslte::proc_manager_list_t callbacks;
srslte::proc_t<custom_proc> proc; srslte::proc_t<custom_proc> proc;
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
@ -263,20 +294,25 @@ int test_callback_3()
} }
TESTASSERT(not proc.is_active()); TESTASSERT(not proc.is_active());
TESTASSERT(not proc.is_complete()); TESTASSERT(not proc.is_complete());
TESTASSERT(proc.get()->obj.id == 0); // Proc is ready to be reused TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused
printf("EXIT\n"); printf("EXIT\n");
TESTASSERT(TestObj::copy_counter == 0); TESTASSERT(TestObj::copy_counter == 0);
TESTASSERT(TestObj::move_counter == 0); TESTASSERT(TestObj::move_counter == 0);
TESTASSERT(TestObj::dtor_counter == 1); // handler not yet destructed TESTASSERT(TestObj::dtor_counter == 0); // handler not yet destructed
return 0; return 0;
} }
int test_callback_4() int test_callback_4()
{ {
/*
* Description: Test for Lambda procedure types
* - test if a lambda that we passed decrements a counter correctly
* - test if when the lambda goes out of scope, procedure still works fine
*/
new_test(); new_test();
printf("\n--- Test %s ---\n", __func__); printf("\n--- Test %s ---\n", __func__);
srslte::callback_list_t callbacks; srslte::proc_manager_list_t callbacks;
int* counter = new int(5); int* counter = new int(5);
{ {
@ -300,6 +336,28 @@ int test_callback_4()
return 0; return 0;
} }
int test_callback_5()
{
/*
* Description: Test if finished procedure does not get added to the dispatch list
*/
new_test();
printf("\n--- Test %s ---\n", __func__);
srslte::proc_manager_list_t callbacks;
srslte::proc_t<custom_proc> proc;
TESTASSERT(proc.launch(5));
while (proc.run()) {
TESTASSERT(proc.is_active());
}
TESTASSERT(proc.is_active());
TESTASSERT(not proc.get()->reset_called);
TESTASSERT(proc.is_complete());
callbacks.defer_proc(proc);
TESTASSERT(callbacks.size() == 0); // do not add finished callbacks
return 0;
}
int main() int main()
{ {
TESTASSERT(test_local_1() == 0); TESTASSERT(test_local_1() == 0);
@ -307,6 +365,7 @@ int main()
TESTASSERT(test_callback_2() == 0); TESTASSERT(test_callback_2() == 0);
TESTASSERT(test_callback_3() == 0); TESTASSERT(test_callback_3() == 0);
TESTASSERT(test_callback_4() == 0); TESTASSERT(test_callback_4() == 0);
TESTASSERT(test_callback_5() == 0);
return 0; return 0;
} }

@ -481,7 +481,8 @@ private:
bool reestablishment_successful = false; bool reestablishment_successful = false;
// Measurements sub-class // Measurements sub-class
class rrc_meas { class rrc_meas
{
public: public:
void init(rrc *parent); void init(rrc *parent);
void reset(); void reset();
@ -633,7 +634,7 @@ private:
srslte::proc_t<plmn_search_proc> plmn_searcher; srslte::proc_t<plmn_search_proc> plmn_searcher;
srslte::proc_t<cell_reselection_proc> cell_reselector; srslte::proc_t<cell_reselection_proc> cell_reselector;
srslte::callback_list_t callback_list; srslte::proc_manager_list_t callback_list;
bool cell_selection_criteria(float rsrp, float rsrq = 0); bool cell_selection_criteria(float rsrp, float rsrq = 0);
void cell_reselection(float rsrp, float rsrq); void cell_reselection(float rsrp, float rsrq);

@ -29,7 +29,7 @@
namespace srsue { namespace srsue {
class rrc::cell_search_proc : public srslte::proc_impl_t class rrc::cell_search_proc
{ {
public: public:
struct cell_search_event_t { struct cell_search_event_t {
@ -38,11 +38,12 @@ public:
}; };
enum class state_t { phy_cell_search, si_acquire }; enum class state_t { phy_cell_search, si_acquire };
srslte::proc_outcome_t init(rrc* parent_); explicit cell_search_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
srslte::proc_outcome_t step();
srslte::proc_outcome_t trigger_event(const cell_search_event_t& event); srslte::proc_outcome_t trigger_event(const cell_search_event_t& event);
phy_interface_rrc_lte::cell_search_ret_t get_cs_ret() { return search_result.cs_ret; } phy_interface_rrc_lte::cell_search_ret_t get_cs_ret() const { return search_result.cs_ret; }
static const char* name() { return "Cell Search"; } static const char* name() { return "Cell Search"; }
private: private:
@ -57,13 +58,14 @@ private:
state_t state; state_t state;
}; };
class rrc::si_acquire_proc : public srslte::proc_impl_t class rrc::si_acquire_proc
{ {
public: public:
const static int SIB_SEARCH_TIMEOUT_MS = 1000; const static int SIB_SEARCH_TIMEOUT_MS = 1000;
srslte::proc_outcome_t init(rrc* parent_, uint32_t sib_index_); explicit si_acquire_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init(uint32_t sib_index_);
srslte::proc_outcome_t step();
static const char* name() { return "SI Acquire"; } static const char* name() { return "SI Acquire"; }
private: private:
@ -74,37 +76,40 @@ private:
srslte::log* log_h; srslte::log* log_h;
// state // state
uint32_t period, sched_index; uint32_t period = 0, sched_index = 0;
uint32_t start_tti = 0; uint32_t start_tti = 0;
uint32_t sib_index = 0; uint32_t sib_index = 0;
uint32_t last_win_start = 0; uint32_t last_win_start = 0;
}; };
class rrc::serving_cell_config_proc : public srslte::proc_impl_t class rrc::serving_cell_config_proc
{ {
public: public:
srslte::proc_outcome_t init(rrc* parent_, const std::vector<uint32_t>& required_sibs_); explicit serving_cell_config_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init(const std::vector<uint32_t>& required_sibs_);
srslte::proc_outcome_t step();
static const char* name() { return "Serving Cell Configuration"; } static const char* name() { return "Serving Cell Configuration"; }
private: private:
// consts
std::vector<uint32_t> required_sibs;
rrc* rrc_ptr; rrc* rrc_ptr;
srslte::log* log_h; srslte::log* log_h;
// proc args
std::vector<uint32_t> required_sibs;
// state variables // state variables
enum class search_state_t { next_sib, si_acquire } search_state; enum class search_state_t { next_sib, si_acquire } search_state;
uint32_t req_idx = 0; uint32_t req_idx = 0;
}; };
class rrc::cell_selection_proc : public srslte::proc_impl_t class rrc::cell_selection_proc
{ {
public: public:
srslte::proc_outcome_t init(rrc* parent_); explicit cell_selection_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
void stop() final; srslte::proc_outcome_t step();
cs_result_t get_cs_result() { return cs_result; } void stop(bool is_success);
cs_result_t get_cs_result() const { return cs_result; }
static const char* name() { return "Cell Selection"; } static const char* name() { return "Cell Selection"; }
private: private:
@ -123,12 +128,13 @@ private:
uint32_t neigh_index; uint32_t neigh_index;
}; };
class rrc::plmn_search_proc : public srslte::proc_impl_t class rrc::plmn_search_proc
{ {
public: public:
srslte::proc_outcome_t init(rrc* parent_); explicit plmn_search_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
void stop() final; srslte::proc_outcome_t step();
void stop(bool is_success);
static const char* name() { return "PLMN Search"; } static const char* name() { return "PLMN Search"; }
private: private:
@ -138,10 +144,10 @@ private:
// state variables // state variables
found_plmn_t found_plmns[MAX_FOUND_PLMNS]; found_plmn_t found_plmns[MAX_FOUND_PLMNS];
int nof_plmns; int nof_plmns = 0;
}; };
class rrc::connection_request_proc : public srslte::proc_impl_t class rrc::connection_request_proc
{ {
public: public:
struct cell_selection_complete { struct cell_selection_complete {
@ -149,17 +155,19 @@ public:
cs_result_t cs_result; cs_result_t cs_result;
}; };
explicit connection_request_proc(rrc* parent_);
srslte::proc_outcome_t srslte::proc_outcome_t
init(rrc* parent_, srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t dedicated_info_nas_); init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t dedicated_info_nas_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t step();
void stop() final; void stop(bool is_success);
srslte::proc_outcome_t trigger_event(const cell_selection_complete& e); srslte::proc_outcome_t trigger_event(const cell_selection_complete& e);
static const char* name() { return "Connection Request"; } static const char* name() { return "Connection Request"; }
private: private:
// args // const
rrc* rrc_ptr; rrc* rrc_ptr;
srslte::log* log_h; srslte::log* log_h;
// args
srslte::establishment_cause_t cause; srslte::establishment_cause_t cause;
srslte::unique_byte_buffer_t dedicated_info_nas; srslte::unique_byte_buffer_t dedicated_info_nas;
@ -168,15 +176,16 @@ private:
cs_result_t cs_ret; cs_result_t cs_ret;
}; };
class rrc::process_pcch_proc : public srslte::proc_impl_t class rrc::process_pcch_proc
{ {
public: public:
struct paging_complete { struct paging_complete {
bool outcome; bool outcome;
}; };
srslte::proc_outcome_t init(rrc* parent_, const asn1::rrc::paging_s& paging_); explicit process_pcch_proc(rrc* parent_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init(const asn1::rrc::paging_s& paging_);
srslte::proc_outcome_t step();
srslte::proc_outcome_t trigger_event(paging_complete e); srslte::proc_outcome_t trigger_event(paging_complete e);
static const char* name() { return "Process PCCH"; } static const char* name() { return "Process PCCH"; }
@ -191,11 +200,12 @@ private:
enum class state_t { next_record, nas_paging, serv_cell_cfg } state; enum class state_t { next_record, nas_paging, serv_cell_cfg } state;
}; };
class rrc::go_idle_proc : public srslte::proc_impl_t class rrc::go_idle_proc
{ {
public: public:
srslte::proc_outcome_t init(rrc* rrc_); explicit go_idle_proc(rrc* rrc_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
srslte::proc_outcome_t step();
static const char* name() { return "Go Idle"; } static const char* name() { return "Go Idle"; }
private: private:
@ -205,11 +215,12 @@ private:
uint32_t rlc_flush_counter; uint32_t rlc_flush_counter;
}; };
class rrc::cell_reselection_proc : public srslte::proc_impl_t class rrc::cell_reselection_proc
{ {
public: public:
srslte::proc_outcome_t init(rrc* rrc_); cell_reselection_proc(rrc* rrc_);
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
srslte::proc_outcome_t step();
static const char* name() { return "Cell Reselection"; } static const char* name() { return "Cell Reselection"; }
private: private:

@ -258,15 +258,16 @@ private:
return list; return list;
} }
class rrc_connect_proc : public srslte::proc_impl_t class rrc_connect_proc
{ {
public: public:
struct connection_request_completed_t { struct connection_request_completed_t {
bool outcome; bool outcome;
}; };
srslte::proc_outcome_t init(nas* nas_ptr_, srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu); rrc_connect_proc(nas* nas_ptr_) : nas_ptr(nas_ptr_) {}
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu);
srslte::proc_outcome_t step();
static const char* name() { return "RRC Connect"; } static const char* name() { return "RRC Connect"; }
private: private:
@ -274,7 +275,7 @@ private:
enum class state_t { conn_req, wait_attach } state; enum class state_t { conn_req, wait_attach } state;
uint32_t wait_timeout; uint32_t wait_timeout;
}; };
class plmn_search_proc : public srslte::proc_impl_t class plmn_search_proc
{ {
public: public:
struct plmn_search_complete_t { struct plmn_search_complete_t {
@ -288,8 +289,9 @@ private:
} }
}; };
srslte::proc_outcome_t init(nas* nas_ptr_); plmn_search_proc(nas* nas_ptr_) : nas_ptr(nas_ptr_) {}
srslte::proc_outcome_t step() final; srslte::proc_outcome_t init();
srslte::proc_outcome_t step();
srslte::proc_outcome_t trigger_event(const plmn_search_complete_t& t); srslte::proc_outcome_t trigger_event(const plmn_search_complete_t& t);
static const char* name() { return "PLMN Search"; } static const char* name() { return "PLMN Search"; }
@ -297,7 +299,7 @@ private:
nas* nas_ptr; nas* nas_ptr;
enum class state_t { plmn_search, rrc_connect } state; enum class state_t { plmn_search, rrc_connect } state;
}; };
srslte::callback_list_t callbacks; srslte::proc_manager_list_t callbacks;
srslte::proc_t<plmn_search_proc> plmn_searcher; srslte::proc_t<plmn_search_proc> plmn_searcher;
srslte::proc_t<rrc_connect_proc> rrc_connector; srslte::proc_t<rrc_connect_proc> rrc_connector;
srslte::proc_t<srslte::query_proc_t<bool> > conn_req_proc; srslte::proc_t<srslte::query_proc_t<bool> > conn_req_proc;
@ -305,5 +307,4 @@ private:
} // namespace srsue } // namespace srsue
#endif // SRSUE_NAS_H #endif // SRSUE_NAS_H

@ -53,6 +53,15 @@ rrc::rrc(srslte::log* rrc_log_) :
last_state(RRC_STATE_CONNECTED), last_state(RRC_STATE_CONNECTED),
drb_up(false), drb_up(false),
rrc_log(rrc_log_), rrc_log(rrc_log_),
cell_searcher(this),
si_acquirer(this),
serv_cell_cfg(this),
cell_selector(this),
idle_setter(this),
pcch_processor(this),
conn_req_proc(this),
plmn_searcher(this),
cell_reselector(this),
serving_cell(unique_cell_t(new cell_t({}, 0.0))) serving_cell(unique_cell_t(new cell_t({}, 0.0)))
{ {
} }
@ -171,11 +180,13 @@ void rrc::get_metrics(rrc_metrics_t& m)
m.state = state; m.state = state;
} }
bool rrc::is_connected() { bool rrc::is_connected()
{
return (RRC_STATE_CONNECTED == state); return (RRC_STATE_CONNECTED == state);
} }
bool rrc::have_drb() { bool rrc::have_drb()
{
return drb_up; return drb_up;
} }
@ -301,7 +312,7 @@ uint16_t rrc::get_mnc() {
*/ */
bool rrc::plmn_search() bool rrc::plmn_search()
{ {
if (not plmn_searcher.launch(this)) { if (not plmn_searcher.launch()) {
rrc_log->error("Unable to initiate PLMN search\n"); rrc_log->error("Unable to initiate PLMN search\n");
return false; return false;
} }
@ -330,7 +341,7 @@ void rrc::plmn_select(srslte::plmn_id_t plmn_id)
*/ */
bool rrc::connection_request(srslte::establishment_cause_t cause, srslte::unique_byte_buffer_t dedicated_info_nas_) bool rrc::connection_request(srslte::establishment_cause_t cause, srslte::unique_byte_buffer_t dedicated_info_nas_)
{ {
if (not conn_req_proc.launch(this, cause, std::move(dedicated_info_nas_))) { if (not conn_req_proc.launch(cause, std::move(dedicated_info_nas_))) {
rrc_log->error("Failed to initiate connection request procedure\n"); rrc_log->error("Failed to initiate connection request procedure\n");
return false; return false;
} }
@ -1193,7 +1204,7 @@ void rrc::start_ho()
void rrc::start_go_idle() void rrc::start_go_idle()
{ {
if (not idle_setter.launch(this)) { if (not idle_setter.launch()) {
rrc_log->info("Failed to set RRC to IDLE\n"); rrc_log->info("Failed to set RRC to IDLE\n");
return; return;
} }
@ -1472,10 +1483,10 @@ void rrc::start_cell_reselection()
return; return;
} }
if (not cell_reselector.launch(this)) { if (not cell_reselector.launch()) {
rrc_log->error("Failed to initiate a Cell Reselection procedure...\n"); rrc_log->error("Failed to initiate a Cell Reselection procedure...\n");
} }
callback_list.defer_proc(cell_reselector); callback_list.add_proc(cell_reselector);
} }
void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret, void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
@ -1743,7 +1754,7 @@ void rrc::process_pcch(unique_byte_buffer_t pdu)
paging->paging_record_list.resize(ASN1_RRC_MAX_PAGE_REC); paging->paging_record_list.resize(ASN1_RRC_MAX_PAGE_REC);
} }
if (not pcch_processor.launch(this, *paging)) { if (not pcch_processor.launch(*paging)) {
rrc_log->error("Failed to launch process PCCH procedure\n"); rrc_log->error("Failed to launch process PCCH procedure\n");
return; return;
} }

@ -35,12 +35,11 @@ using srslte::proc_outcome_t;
* Cell Search Procedure * Cell Search Procedure
*************************************/ *************************************/
rrc::cell_search_proc::cell_search_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
/* Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet */ /* Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet */
proc_outcome_t rrc::cell_search_proc::init(srsue::rrc* parent_) proc_outcome_t rrc::cell_search_proc::init()
{ {
rrc_ptr = parent_;
log_h = parent_->rrc_log;
Info("Starting...\n"); Info("Starting...\n");
state = state_t::phy_cell_search; state = state_t::phy_cell_search;
rrc_ptr->stack->start_cell_search(); rrc_ptr->stack->start_cell_search();
@ -56,7 +55,7 @@ proc_outcome_t rrc::cell_search_proc::step()
} else if (state == state_t::si_acquire) { } else if (state == state_t::si_acquire) {
if (not rrc_ptr->si_acquirer.run()) { if (not rrc_ptr->si_acquirer.run()) {
// SI Acquire has completed // SI Acquire has completed
si_acquire_proc ret = rrc_ptr->si_acquirer.pop(); srslte::proc_result_t<si_acquire_proc> ret = rrc_ptr->si_acquirer.pop();
if (ret.is_error()) { if (ret.is_error()) {
Error("Failed to trigger SI acquire for SIB0\n"); Error("Failed to trigger SI acquire for SIB0\n");
return proc_outcome_t::error; return proc_outcome_t::error;
@ -93,7 +92,7 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_
return proc_outcome_t::success; return proc_outcome_t::success;
} }
if (not rrc_ptr->si_acquirer.launch(rrc_ptr, 0)) { if (not rrc_ptr->si_acquirer.launch(0)) {
// disallow concurrent si_acquire // disallow concurrent si_acquire
Error("SI Acquire is already running...\n"); Error("SI Acquire is already running...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
@ -135,14 +134,16 @@ proc_outcome_t rrc::cell_search_proc::trigger_event(const cell_search_event_t& e
* SI Acquire Procedure * SI Acquire Procedure
*************************************/ *************************************/
proc_outcome_t rrc::si_acquire_proc::init(rrc* parent_, uint32_t sib_index_) rrc::si_acquire_proc::si_acquire_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
{
rrc_ptr = parent_;
log_h = parent_->rrc_log;
proc_outcome_t rrc::si_acquire_proc::init(uint32_t sib_index_)
{
Info("Starting SI Acquire procedure for SIB%d\n", sib_index_ + 1); Info("Starting SI Acquire procedure for SIB%d\n", sib_index_ + 1);
sib_index = sib_index_; sib_index = sib_index_;
start_tti = rrc_ptr->mac->get_current_tti(); start_tti = rrc_ptr->mac->get_current_tti();
period = 0;
sched_index = 0;
last_win_start = 0;
// set period/sched_index // set period/sched_index
if (sib_index == 0) { if (sib_index == 0) {
@ -242,13 +243,13 @@ uint32_t rrc::si_acquire_proc::sib_start_tti(uint32_t tti, uint32_t period, uint
* Serving Cell Config Procedure * Serving Cell Config Procedure
*************************************/ *************************************/
rrc::serving_cell_config_proc::serving_cell_config_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
/* /*
* Retrieves all required SIB or configures them if already retrieved before * Retrieves all required SIB or configures them if already retrieved before
*/ */
proc_outcome_t rrc::serving_cell_config_proc::init(srsue::rrc* parent_, const std::vector<uint32_t>& required_sibs_) proc_outcome_t rrc::serving_cell_config_proc::init(const std::vector<uint32_t>& required_sibs_)
{ {
rrc_ptr = parent_;
log_h = parent_->rrc_log;
required_sibs = required_sibs_; required_sibs = required_sibs_;
Info("Starting a Serving Cell Configuration Procedure\n"); Info("Starting a Serving Cell Configuration Procedure\n");
@ -274,7 +275,7 @@ proc_outcome_t rrc::serving_cell_config_proc::step()
if (not rrc_ptr->serving_cell->has_sib(required_sib)) { if (not rrc_ptr->serving_cell->has_sib(required_sib)) {
Info("Cell has no SIB%d. Obtaining SIB%d\n", required_sib + 1, required_sib + 1); Info("Cell has no SIB%d. Obtaining SIB%d\n", required_sib + 1, required_sib + 1);
if (not rrc_ptr->si_acquirer.launch(rrc_ptr, required_sib)) { if (not rrc_ptr->si_acquirer.launch(required_sib)) {
Error("SI Acquire is already running...\n"); Error("SI Acquire is already running...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -302,7 +303,7 @@ proc_outcome_t rrc::serving_cell_config_proc::step()
} else if (search_state == search_state_t::si_acquire) { } else if (search_state == search_state_t::si_acquire) {
uint32_t required_sib = required_sibs[req_idx]; uint32_t required_sib = required_sibs[req_idx];
if (not rrc_ptr->si_acquirer.run()) { if (not rrc_ptr->si_acquirer.run()) {
si_acquire_proc ret = rrc_ptr->si_acquirer.pop(); srslte::proc_result_t<si_acquire_proc> ret = rrc_ptr->si_acquirer.pop();
if (ret.is_error() or not rrc_ptr->serving_cell->has_sib(required_sib)) { if (ret.is_error() or not rrc_ptr->serving_cell->has_sib(required_sib)) {
if (required_sib < 2) { if (required_sib < 2) {
log_h->warning("Serving Cell Configuration has failed\n"); log_h->warning("Serving Cell Configuration has failed\n");
@ -322,15 +323,14 @@ proc_outcome_t rrc::serving_cell_config_proc::step()
* Cell Selection Procedure * Cell Selection Procedure
*************************************/ *************************************/
rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
/* /*
* Cell selection procedure 36.304 5.2.3 * Cell selection procedure 36.304 5.2.3
* Select the best cell to camp on among the list of known cells * Select the best cell to camp on among the list of known cells
*/ */
proc_outcome_t rrc::cell_selection_proc::init(srsue::rrc* parent_) proc_outcome_t rrc::cell_selection_proc::init()
{ {
rrc_ptr = parent_;
log_h = parent_->rrc_log;
if (rrc_ptr->neighbour_cells.empty() and rrc_ptr->serving_cell->in_sync and rrc_ptr->phy->cell_is_camping()) { if (rrc_ptr->neighbour_cells.empty() and rrc_ptr->serving_cell->in_sync and rrc_ptr->phy->cell_is_camping()) {
// don't bother with cell selection if there are no neighbours and we are already camping // don't bother with cell selection if there are no neighbours and we are already camping
Debug("Skipping Cell Selection Procedure ..\n"); Debug("Skipping Cell Selection Procedure ..\n");
@ -365,7 +365,7 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
/* BLOCKING CALL */ /* BLOCKING CALL */
if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) { if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) {
if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr, rrc_ptr->ue_required_sibs)) { if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr->ue_required_sibs)) {
return proc_outcome_t::error; return proc_outcome_t::error;
} }
state = search_state_t::cell_config; state = search_state_t::cell_config;
@ -397,7 +397,7 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
// If can not find any suitable cell, search again // If can not find any suitable cell, search again
Info("Cell selection and reselection in IDLE did not find any suitable cell. Searching again\n"); Info("Cell selection and reselection in IDLE did not find any suitable cell. Searching again\n");
if (not rrc_ptr->cell_searcher.launch(rrc_ptr)) { if (not rrc_ptr->cell_searcher.launch()) {
return proc_outcome_t::error; return proc_outcome_t::error;
} }
state = search_state_t::cell_search; state = search_state_t::cell_search;
@ -410,12 +410,12 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_search()
if (rrc_ptr->cell_searcher.run()) { if (rrc_ptr->cell_searcher.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
cell_search_proc ret = rrc_ptr->cell_searcher.pop(); srslte::proc_result_t<cell_search_proc> ret = rrc_ptr->cell_searcher.pop();
if (ret.is_error()) { if (ret.is_error()) {
cs_result = cs_result_t::no_cell; cs_result = cs_result_t::no_cell;
return proc_outcome_t::error; return proc_outcome_t::error;
} else { } else {
cs_result = (ret.get_cs_ret().found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) cs_result = (ret.proc()->get_cs_ret().found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND)
? cs_result_t::changed_cell ? cs_result_t::changed_cell
: cs_result_t::no_cell; : cs_result_t::no_cell;
Info("Cell Search of cell selection run successfully\n"); Info("Cell Search of cell selection run successfully\n");
@ -428,7 +428,7 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_config()
if (rrc_ptr->serv_cell_cfg.run()) { if (rrc_ptr->serv_cell_cfg.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
serving_cell_config_proc ret = rrc_ptr->serv_cell_cfg.pop(); srslte::proc_result_t<serving_cell_config_proc> ret = rrc_ptr->serv_cell_cfg.pop();
if (ret.is_success()) { if (ret.is_success()) {
Info("All SIBs of serving cell obtained successfully\n"); Info("All SIBs of serving cell obtained successfully\n");
cs_result = cs_result_t::changed_cell; cs_result = cs_result_t::changed_cell;
@ -455,27 +455,26 @@ proc_outcome_t rrc::cell_selection_proc::step()
return proc_outcome_t::error; return proc_outcome_t::error;
} }
void rrc::cell_selection_proc::stop() void rrc::cell_selection_proc::stop(bool is_success)
{ {
// Inform Connection Request Procedure // Inform Connection Request Procedure
Info("Completed with %s. Informing proc %s\n", Info("Completed with %s. Informing proc %s\n",
is_success() ? "success" : "failure", is_success ? "success" : "failure",
rrc_ptr->conn_req_proc.get()->name()); rrc_ptr->conn_req_proc.get()->name());
rrc_ptr->conn_req_proc.trigger_event(connection_request_proc::cell_selection_complete{is_success(), cs_result}); rrc_ptr->conn_req_proc.trigger_event(connection_request_proc::cell_selection_complete{is_success, cs_result});
} }
/************************************** /**************************************
* PLMN search Procedure * PLMN search Procedure
*************************************/ *************************************/
proc_outcome_t rrc::plmn_search_proc::init(srsue::rrc* parent_) rrc::plmn_search_proc::plmn_search_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
{
rrc_ptr = parent_;
log_h = parent_->rrc_log;
proc_outcome_t rrc::plmn_search_proc::init()
{
Info("Starting PLMN search\n"); Info("Starting PLMN search\n");
nof_plmns = 0; nof_plmns = 0;
if (not rrc_ptr->cell_searcher.launch(rrc_ptr)) { if (not rrc_ptr->cell_searcher.launch()) {
Error("Failed due to fail to init cell search...\n"); Error("Failed due to fail to init cell search...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -493,8 +492,8 @@ proc_outcome_t rrc::plmn_search_proc::step()
// wait for new TTI // wait for new TTI
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
cell_search_proc ret = rrc_ptr->cell_searcher.pop(); srslte::proc_result_t<cell_search_proc> ret = rrc_ptr->cell_searcher.pop();
phy_interface_rrc_lte::cell_search_ret_t cs_ret = ret.get_cs_ret(); phy_interface_rrc_lte::cell_search_ret_t cs_ret = ret.proc()->get_cs_ret();
if (ret.is_error() or cs_ret.found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) { if (ret.is_error() or cs_ret.found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) {
// stop search // stop search
nof_plmns = -1; nof_plmns = -1;
@ -524,7 +523,7 @@ proc_outcome_t rrc::plmn_search_proc::step()
return proc_outcome_t::success; return proc_outcome_t::success;
} }
if (not rrc_ptr->cell_searcher.launch(rrc_ptr)) { if (not rrc_ptr->cell_searcher.launch()) {
Error("Failed due to fail to init cell search...\n"); Error("Failed due to fail to init cell search...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -533,13 +532,13 @@ proc_outcome_t rrc::plmn_search_proc::step()
return proc_outcome_t::repeat; return proc_outcome_t::repeat;
} }
void rrc::plmn_search_proc::stop() void rrc::plmn_search_proc::stop(bool is_success)
{ {
// on cleanup, call plmn_search_completed // on cleanup, call plmn_search_completed
if (is_success()) { if (is_success) {
Info("completed with success\n"); Info("completed with success\n");
rrc_ptr->nas->plmn_search_completed(found_plmns, nof_plmns); rrc_ptr->nas->plmn_search_completed(found_plmns, nof_plmns);
} else if (is_error()) { } else {
Error("PLMN Search completed with an error\n"); Error("PLMN Search completed with an error\n");
rrc_ptr->nas->plmn_search_completed(nullptr, -1); rrc_ptr->nas->plmn_search_completed(nullptr, -1);
} }
@ -549,12 +548,11 @@ void rrc::plmn_search_proc::stop()
* Connection Request Procedure * Connection Request Procedure
*************************************/ *************************************/
proc_outcome_t rrc::connection_request_proc::init(rrc* parent_, rrc::connection_request_proc::connection_request_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
srslte::establishment_cause_t cause_,
proc_outcome_t rrc::connection_request_proc::init(srslte::establishment_cause_t cause_,
srslte::unique_byte_buffer_t dedicated_info_nas_) srslte::unique_byte_buffer_t dedicated_info_nas_)
{ {
rrc_ptr = parent_;
log_h = parent_->rrc_log;
cause = cause_; cause = cause_;
dedicated_info_nas = std::move(dedicated_info_nas_); dedicated_info_nas = std::move(dedicated_info_nas_);
@ -579,7 +577,7 @@ proc_outcome_t rrc::connection_request_proc::init(rrc*
cs_ret = cs_result_t::no_cell; cs_ret = cs_result_t::no_cell;
state = state_t::cell_selection; state = state_t::cell_selection;
if (not rrc_ptr->cell_selector.launch(rrc_ptr)) { if (not rrc_ptr->cell_selector.launch()) {
if (not rrc_ptr->cell_selector.is_active()) { if (not rrc_ptr->cell_selector.is_active()) {
// Launch failed but cell selection was not already running // Launch failed but cell selection was not already running
Error("Failed to initiate cell selection procedure...\n"); Error("Failed to initiate cell selection procedure...\n");
@ -591,8 +589,8 @@ proc_outcome_t rrc::connection_request_proc::init(rrc*
// It already completed with success. FIXME: Find more elegant solution // It already completed with success. FIXME: Find more elegant solution
Info("A cell selection procedure has just finished successfully. I am reusing its result\n"); Info("A cell selection procedure has just finished successfully. I am reusing its result\n");
cell_selection_complete e{}; cell_selection_complete e{};
e.is_success = rrc_ptr->cell_selector.get()->is_success();
e.cs_result = rrc_ptr->cell_selector.get()->get_cs_result(); e.cs_result = rrc_ptr->cell_selector.get()->get_cs_result();
e.is_success = e.cs_result == cs_result_t::same_cell or e.cs_result == cs_result_t::changed_cell;
return trigger_event(e); return trigger_event(e);
} }
} else { } else {
@ -611,7 +609,7 @@ proc_outcome_t rrc::connection_request_proc::step()
if (rrc_ptr->serv_cell_cfg.run()) { if (rrc_ptr->serv_cell_cfg.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
serving_cell_config_proc ret = rrc_ptr->serv_cell_cfg.pop(); srslte::proc_result_t<serving_cell_config_proc> ret = rrc_ptr->serv_cell_cfg.pop();
if (ret.is_error()) { if (ret.is_error()) {
Error("Configuring serving cell\n"); Error("Configuring serving cell\n");
@ -660,13 +658,13 @@ proc_outcome_t rrc::connection_request_proc::step()
return proc_outcome_t::error; return proc_outcome_t::error;
} }
void rrc::connection_request_proc::stop() void rrc::connection_request_proc::stop(bool is_success)
{ {
if (is_error()) { if (not is_success) {
log_h->warning("Could not establish connection. Deallocating dedicatedInfoNAS PDU\n"); log_h->warning("Could not establish connection. Deallocating dedicatedInfoNAS PDU\n");
this->dedicated_info_nas.reset(); this->dedicated_info_nas.reset();
rrc_ptr->nas->connection_request_completed(false); rrc_ptr->nas->connection_request_completed(false);
} else if (is_success()) { } else {
Info("Finished connection request procedure successfully.\n"); Info("Finished connection request procedure successfully.\n");
rrc_ptr->nas->connection_request_completed(true); rrc_ptr->nas->connection_request_completed(true);
} }
@ -693,7 +691,7 @@ srslte::proc_outcome_t rrc::connection_request_proc::trigger_event(const cell_se
// timeAlignmentCommon applied in configure_serving_cell // timeAlignmentCommon applied in configure_serving_cell
Info("Configuring serving cell...\n"); Info("Configuring serving cell...\n");
if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr, rrc_ptr->ue_required_sibs)) { if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr->ue_required_sibs)) {
Error("Attach request failed to configure serving cell...\n"); Error("Attach request failed to configure serving cell...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -720,10 +718,10 @@ srslte::proc_outcome_t rrc::connection_request_proc::trigger_event(const cell_se
* Process PCCH procedure * Process PCCH procedure
*************************************/ *************************************/
proc_outcome_t rrc::process_pcch_proc::init(rrc* parent_, const asn1::rrc::paging_s& paging_) rrc::process_pcch_proc::process_pcch_proc(srsue::rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {}
proc_outcome_t rrc::process_pcch_proc::init(const asn1::rrc::paging_s& paging_)
{ {
rrc_ptr = parent_;
log_h = parent_->rrc_log;
paging = paging_; paging = paging_;
paging_idx = 0; paging_idx = 0;
@ -762,7 +760,7 @@ proc_outcome_t rrc::process_pcch_proc::step()
rrc_ptr->serving_cell->reset_sibs(); rrc_ptr->serving_cell->reset_sibs();
// create a serving cell config procedure and push it to callback list // create a serving cell config procedure and push it to callback list
if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr, rrc_ptr->ue_required_sibs)) { if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr->ue_required_sibs)) {
Error("Failed to initiate a serving cell configuration procedure\n"); Error("Failed to initiate a serving cell configuration procedure\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -779,7 +777,7 @@ proc_outcome_t rrc::process_pcch_proc::step()
if (rrc_ptr->serv_cell_cfg.run()) { if (rrc_ptr->serv_cell_cfg.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
serving_cell_config_proc ret = rrc_ptr->serv_cell_cfg.pop(); srslte::proc_result_t<serving_cell_config_proc> ret = rrc_ptr->serv_cell_cfg.pop();
if (ret.is_success()) { if (ret.is_success()) {
Info("All SIBs of serving cell obtained successfully\n"); Info("All SIBs of serving cell obtained successfully\n");
return proc_outcome_t::success; return proc_outcome_t::success;
@ -807,10 +805,10 @@ proc_outcome_t rrc::process_pcch_proc::trigger_event(paging_complete e)
* Go Idle procedure * Go Idle procedure
*************************************/ *************************************/
proc_outcome_t rrc::go_idle_proc::init(rrc* rrc_) rrc::go_idle_proc::go_idle_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_) {}
{
rrc_ptr = rrc_;
proc_outcome_t rrc::go_idle_proc::init()
{
rlc_flush_counter = 0; rlc_flush_counter = 0;
Info("Starting...\n"); Info("Starting...\n");
return proc_outcome_t::yield; return proc_outcome_t::yield;
@ -838,12 +836,13 @@ proc_outcome_t rrc::go_idle_proc::step()
* Cell Reselection procedure * Cell Reselection procedure
*************************************/ *************************************/
proc_outcome_t rrc::cell_reselection_proc::init(srsue::rrc* rrc_) rrc::cell_reselection_proc::cell_reselection_proc(srsue::rrc* rrc_)
{ : rrc_ptr(rrc_) {}
rrc_ptr = rrc_;
proc_outcome_t rrc::cell_reselection_proc::init()
{
Info("Cell Reselection - Starting...\n"); Info("Cell Reselection - Starting...\n");
if (not rrc_ptr->cell_selector.launch(rrc_ptr)) { if (not rrc_ptr->cell_selector.launch()) {
Error("Failed to initiate a Cell Selection procedure...\n"); Error("Failed to initiate a Cell Selection procedure...\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -856,13 +855,13 @@ proc_outcome_t rrc::cell_reselection_proc::step()
if (rrc_ptr->cell_selector.run()) { if (rrc_ptr->cell_selector.run()) {
return srslte::proc_outcome_t::yield; return srslte::proc_outcome_t::yield;
} }
cell_selection_proc ret = rrc_ptr->cell_selector.pop(); srslte::proc_result_t<cell_selection_proc> ret = rrc_ptr->cell_selector.pop();
if (ret.is_error()) { if (ret.is_error()) {
Error("Cell Reselection - Error while selecting a cell\n"); Error("Cell Reselection - Error while selecting a cell\n");
return srslte::proc_outcome_t::error; return srslte::proc_outcome_t::error;
} }
switch (ret.get_cs_result()) { switch (ret.proc()->get_cs_result()) {
case cs_result_t::changed_cell: case cs_result_t::changed_cell:
// New cell has been selected, start receiving PCCH // New cell has been selected, start receiving PCCH
rrc_ptr->mac->pcch_start_rx(); rrc_ptr->mac->pcch_start_rx();

@ -44,10 +44,8 @@ namespace srsue {
using srslte::proc_outcome_t; using srslte::proc_outcome_t;
proc_outcome_t nas::plmn_search_proc::init(nas* nas_ptr_) proc_outcome_t nas::plmn_search_proc::init()
{ {
nas_ptr = nas_ptr_;
// start RRC // start RRC
state = state_t::plmn_search; state = state_t::plmn_search;
if (not nas_ptr->rrc->plmn_search()) { if (not nas_ptr->rrc->plmn_search()) {
@ -65,7 +63,7 @@ proc_outcome_t nas::plmn_search_proc::step()
if (nas_ptr->rrc_connector.run()) { if (nas_ptr->rrc_connector.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
rrc_connect_proc ret = nas_ptr->rrc_connector.pop(); proc_result_t<rrc_connect_proc> ret = nas_ptr->rrc_connector.pop();
if (ret.is_success()) { if (ret.is_success()) {
return proc_outcome_t::success; return proc_outcome_t::success;
} }
@ -116,7 +114,7 @@ proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t
nas_ptr->rrc->plmn_select(nas_ptr->current_plmn); nas_ptr->rrc->plmn_select(nas_ptr->current_plmn);
if (not nas_ptr->rrc_connector.launch(nas_ptr, srslte::establishment_cause_t ::mo_data, nullptr)) { if (not nas_ptr->rrc_connector.launch(srslte::establishment_cause_t::mo_data, nullptr)) {
ProcError("Unable to initiate RRC connection.\n"); ProcError("Unable to initiate RRC connection.\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -125,11 +123,8 @@ proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
proc_outcome_t proc_outcome_t nas::rrc_connect_proc::init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu)
nas::rrc_connect_proc::init(nas* nas_ptr_, srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu)
{ {
nas_ptr = nas_ptr_;
if (nas_ptr->rrc->is_connected()) { if (nas_ptr->rrc->is_connected()) {
ProcInfo("Stopping. Reason: Already connected\n"); ProcInfo("Stopping. Reason: Already connected\n");
return proc_outcome_t::success; return proc_outcome_t::success;
@ -173,8 +168,8 @@ proc_outcome_t nas::rrc_connect_proc::step()
if (nas_ptr->conn_req_proc.run()) { if (nas_ptr->conn_req_proc.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
query_proc_t<bool> ret = nas_ptr->conn_req_proc.pop(); proc_result_t<query_proc_t<bool>> ret = nas_ptr->conn_req_proc.pop();
if (not ret.result()) { if (ret.is_error()) {
ProcError("Could not establish RRC connection\n"); ProcError("Could not establish RRC connection\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -195,7 +190,7 @@ proc_outcome_t nas::rrc_connect_proc::step()
} else if (nas_ptr->state == EMM_STATE_DEREGISTERED) { } else if (nas_ptr->state == EMM_STATE_DEREGISTERED) {
ProcError("Timeout or received attach reject while trying to attach\n"); ProcError("Timeout or received attach reject while trying to attach\n");
nas_ptr->nas_log->console("Failed to Attach\n"); nas_ptr->nas_log->console("Failed to Attach\n");
} else if (!nas_ptr->rrc->is_connected()) { } else if (!nas_ptr->rrc->is_connected()){
ProcError("Was disconnected while attaching\n"); ProcError("Was disconnected while attaching\n");
} else { } else {
ProcError("Timed out while trying to attach\n"); ProcError("Timed out while trying to attach\n");
@ -213,6 +208,8 @@ proc_outcome_t nas::rrc_connect_proc::step()
nas::nas(srslte::log* log_, srslte::timers* timers_) : nas::nas(srslte::log* log_, srslte::timers* timers_) :
nas_log(log_), nas_log(log_),
pool(byte_buffer_pool::get_instance()), pool(byte_buffer_pool::get_instance()),
plmn_searcher(this),
rrc_connector(this),
timers(timers_) timers(timers_)
{ {
} }
@ -342,7 +339,7 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme
// Search PLMN is not selected // Search PLMN is not selected
if (!plmn_is_selected) { if (!plmn_is_selected) {
nas_log->info("No PLMN selected. Starting PLMN Search...\n"); nas_log->info("No PLMN selected. Starting PLMN Search...\n");
if (not plmn_searcher.launch(this)) { if (not plmn_searcher.launch()) {
if (result != nullptr) { if (result != nullptr) {
*result = proc_state_t::error; *result = proc_state_t::error;
} }
@ -352,7 +349,7 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme
if (plmn_searcher.run()) { if (plmn_searcher.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
plmn_search_proc p = plmn_searcher.pop(); proc_result_t<plmn_search_proc> p = plmn_searcher.pop();
nas_log->info("Attach Request from PLMN Search %s\n", p.is_success() ? "finished successfully" : "failed"); nas_log->info("Attach Request from PLMN Search %s\n", p.is_success() ? "finished successfully" : "failed");
if (result != nullptr) { if (result != nullptr) {
*result = p.is_success() ? proc_state_t::success : proc_state_t::error; *result = p.is_success() ? proc_state_t::success : proc_state_t::error;
@ -382,7 +379,7 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme
} }
} else { } else {
nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n"); nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n");
if (not rrc_connector.launch(this, cause_, nullptr)) { if (not rrc_connector.launch(cause_, nullptr)) {
nas_log->error("Cannot initiate concurrent rrc connection procedures\n"); nas_log->error("Cannot initiate concurrent rrc connection procedures\n");
if (result != nullptr) { if (result != nullptr) {
*result = proc_state_t::error; *result = proc_state_t::error;
@ -393,7 +390,7 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme
if (rrc_connector.run()) { if (rrc_connector.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
rrc_connect_proc proc = rrc_connector.pop(); proc_result_t<rrc_connect_proc> proc = rrc_connector.pop();
if (proc.is_success()) { if (proc.is_success()) {
nas_log->info("NAS attached successfully.\n"); nas_log->info("NAS attached successfully.\n");
} else { } else {
@ -465,7 +462,7 @@ void nas::paging(s_tmsi_t* ue_identity)
nas_log->error("Cannot initiate concurrent RRC connection establishment procedures\n"); nas_log->error("Cannot initiate concurrent RRC connection establishment procedures\n");
return; return;
} }
if (not rrc_connector.launch(this, srslte::establishment_cause_t ::mt_access, nullptr)) { if (not rrc_connector.launch(srslte::establishment_cause_t::mt_access, nullptr)) {
nas_log->error("Could not launch RRC Connect()\n"); nas_log->error("Could not launch RRC Connect()\n");
return; return;
} }
@ -1793,7 +1790,7 @@ void nas::send_detach_request(bool switch_off)
if (rrc->is_connected()) { if (rrc->is_connected()) {
rrc->write_sdu(std::move(pdu)); rrc->write_sdu(std::move(pdu));
} else { } else {
if (not rrc_connector.launch(this, establishment_cause_t::mo_sig, std::move(pdu))) { if (not rrc_connector.launch(establishment_cause_t::mo_sig, std::move(pdu))) {
nas_log->error("Failed to initiate RRC Connection Request\n"); nas_log->error("Failed to initiate RRC Connection Request\n");
} }
callbacks.defer_proc(rrc_connector); callbacks.defer_proc(rrc_connector);

Loading…
Cancel
Save