From f2d88e5a5bb058784307437af722e84794c7be82 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 2 Oct 2019 11:06:39 +0100 Subject: [PATCH] simplified NAS rrc connection request procedure move non-type-specific methods of proc_t to its base class. procedure state machine was simplified via a future-type. Now procedures dont get stuck until the user reads the procedure outcome. made the NAS procedures more event trigger/reaction-based. --- lib/include/srslte/common/stack_procedure.h | 464 ++++++++++-------- lib/include/srslte/interfaces/ue_interfaces.h | 15 +- lib/test/common/stack_procedure_test.cc | 279 ++++++----- srsue/hdr/stack/rrc/rrc.h | 8 +- srsue/hdr/stack/rrc/rrc_procedures.h | 57 ++- srsue/hdr/stack/upper/nas.h | 26 +- srsue/src/stack/rrc/rrc.cc | 16 +- srsue/src/stack/rrc/rrc_procedures.cc | 185 ++++--- srsue/src/stack/upper/nas.cc | 201 ++++---- srsue/test/upper/nas_test.cc | 12 +- 10 files changed, 661 insertions(+), 602 deletions(-) diff --git a/lib/include/srslte/common/stack_procedure.h b/lib/include/srslte/common/stack_procedure.h index 0e2c44513..2bba82d2e 100644 --- a/lib/include/srslte/common/stack_procedure.h +++ b/lib/include/srslte/common/stack_procedure.h @@ -30,23 +30,23 @@ namespace srslte { -enum class proc_state_t { on_going, success, error, inactive }; enum class proc_outcome_t { repeat, yield, success, error }; /************************************************************************************** - * helper functions for overloading + * helper functions for method optional overloading ************************************************************************************/ namespace detail { -// used by proc_manager to call proc finally() method only if it exists -template -auto optional_complete(T* obj, int is_success) -> decltype(obj->on_complete(is_success)) +// used by proc_t to call T::then() method only if it exists +template +auto optional_then(T* obj, const ProcResult& result) -> decltype(obj->then(result)) { - obj->on_complete(is_success); + obj->then(result); } -inline auto optional_complete(...) -> void +inline auto optional_then(...) -> void { // do nothing } +// used by proc_t to call proc T::clear() method only if it exists template auto optional_clear(T* obj) -> decltype(obj->clear()) { @@ -56,27 +56,34 @@ inline auto optional_clear(...) -> void { // do nothing } +template +auto get_result_type(const T& obj) -> decltype(obj.get_result()); +inline auto get_result_type(...) -> void; } // namespace detail /************************************************************************************** - * class: callback_list_t + * class: callback_group_t + * Bundles several callbacks with callable interface "void(Args...)". + * Calls to operator(Args&&...) call all the registered callbacks. + * Two methods to register a callback - call it once, or always call it. ************************************************************************************/ -template -class callback_list_t +template +class callback_group_t { public: - using id_type = uint32_t; - using callback_t = Func; - // register new callbacks - id_type call_once(callback_t f_) + using callback_id_t = uint32_t; + using callback_t = std::function; + + //! register callback, that gets called once + callback_id_t on_next_call(callback_t f_) { uint32_t idx = get_new_callback(); func_list[idx].func = std::move(f_); func_list[idx].call_always = false; return idx; } - id_type call_always(callback_t f_) + callback_id_t on_every_call(callback_t f_) { uint32_t idx = get_new_callback(); func_list[idx].func = std::move(f_); @@ -85,11 +92,12 @@ public: } // call all callbacks - void run(bool is_success) + template + void operator()(const ArgsRef&... args) { for (auto& f : func_list) { if (f.active) { - f.func(is_success); + f.func(args...); if (not f.call_always) { f.active = false; } @@ -111,20 +119,90 @@ private: } struct call_item_t { - bool active; - std::function func; - bool call_always; + bool active; + callback_t func; + bool call_always; }; std::vector func_list; }; /************************************************************************************** - * class: proc_itf_t + * class: proc_result_t + * Stores the result of a procedure run. Can optionally contain a value T, in case of a + * successful run. + **************************************************************************************/ + +namespace detail { +struct proc_result_base_t { + bool is_success() const { return state == result_state_t::value; } + bool is_error() const { return state == result_state_t::error; } + bool is_complete() const { return state != result_state_t::none; } + void set_val() { state = result_state_t::value; } + void set_error() { state = result_state_t::error; } + void clear() { state = result_state_t::none; } + +protected: + enum class result_state_t { none, value, error } state = result_state_t::none; +}; +} // namespace detail +template +struct proc_result_t : public detail::proc_result_base_t { + const T* value() const { return state == result_state_t::value ? &t : nullptr; } + void set_val(const T& t_) + { + proc_result_base_t::set_val(); + t = t_; + } + template + void extract_val(Proc& p) + { + set_val(p.get_result()); + } + +protected: + T t; +}; +template <> +struct proc_result_t : public detail::proc_result_base_t { + template + void extract_val(Proc& p) + { + set_val(); + } +}; + +/************************************************************************************** + * class: proc_future_t + * Contains a pointer to the result of a procedure run. This pointer gets updated with + * the actual result once the procedure completes. + **************************************************************************************/ +template +class proc_future_t +{ +public: + proc_future_t() = default; + explicit proc_future_t(const std::shared_ptr >& p_) : ptr(p_) {} + bool is_error() const { return ptr->is_error(); } + bool is_success() const { return ptr->is_success(); } + bool is_complete() const { return ptr->is_complete(); } + const ResultType* value() const { return is_success() ? ptr->value() : nullptr; } + +private: + std::shared_ptr > ptr; +}; +using proc_future_state_t = proc_future_t; + +/************************************************************************************** + * class: proc_base_t * Provides a polymorphic interface for resumable procedures. This base can then be used - * by a procedure manager container via the virtual method "proc_itf_t::run()". - * With methods: - * - run() - executes a procedure, returning true if the procedure is still running - * or false, if it has completed + * by a "proc_manager_list_t" via the virtual method "proc_base_t::run()". + * With public methods: + * - run() - executes proc_t::step(), and updates procedure state. + * - is_busy()/is_idle() - tells if procedure is currently running. Busy procedures + * cannot be re-launched + * - then() - called automatically when a procedure has finished. Useful for actions + * upon procedure completion, like sending back a response or logging. + * With protected methods: * - step() - method overriden by child class that will be called by run(). step() * executes a procedure "action" based on its current internal state, * and return a proc_outcome_t variable with possible values: @@ -133,77 +211,88 @@ private: * recall step() again (probably the procedure state has changed) * - error - the procedure has finished unsuccessfully * - success - the procedure has completed successfully - * - finally() - called automatically when a procedure has finished. Useful for actions - * upon procedure completion, like sending back a response. - * - set_proc_state() / is_#() - setter and getters for current procedure state ************************************************************************************/ -class proc_manager_itf_t +class proc_base_t { public: - virtual bool run() = 0; - virtual ~proc_manager_itf_t() = default; -}; + virtual ~proc_base_t() = default; -template -struct proc_result_t; - -/************************************************************************************** - * class: proc_manager_t - * Manages the lifetime, of a procedure T, including its alloc, launching, - * and reset back to initial, uninit state once the procedure has been - * completed and the user has extracted its results. - * Every procedure starts in inactive state, and finishes with success or error. - * Can only be re-launched when a procedure T becomes inactive. - * It uses a unique_ptr to allow the use of procedures that are forward declared. - * It provides the following methods: - * - run() - calls T::step() and update the procedure state. - * - launch() - initializes the procedure T by calling T::init(...). Handles the case - * of failed initialization, and forbids the initialization of procedures - * that are already active. - * - pop() - extracts the result of the procedure if it has finished, and sets - * proc_t back to inactive - * - trigger_event(Event) - used for handling external events. The procedure T will - * have to define a method "trigger_event(Event)" as well, - * specifying how each event type should be handled. - ************************************************************************************/ -template -class proc_t final : public proc_manager_itf_t -{ - using complete_callback_list_t = callback_list_t >; - -public: - template - explicit proc_t(Args&&... args) : proc_impl_ptr(new T(std::forward(args)...)) - { - } - - bool run() override + //! common proc::run() interface. Returns true if procedure is still running + bool run() { proc_outcome_t outcome = proc_outcome_t::repeat; - while (is_running() and outcome == proc_outcome_t::repeat) { - outcome = proc_impl_ptr->step(); + while (is_busy() and outcome == proc_outcome_t::repeat) { + outcome = step(); handle_outcome(outcome); } - return is_running(); + return is_busy(); } - void clear() + //! interface to check if proc is still running + bool is_busy() const { return proc_state == proc_status_t::on_going; } + bool is_idle() const { return proc_state == proc_status_t::idle; } + +protected: + enum class proc_status_t { idle, on_going }; + virtual proc_outcome_t step() = 0; + virtual void run_then(bool is_success) = 0; + + void handle_outcome(proc_outcome_t outcome) { - // resets procedure and sets proc_t back to inactive - detail::optional_clear(proc_impl_ptr.get()); - proc_state = proc_state_t::inactive; + if (outcome == proc_outcome_t::error or outcome == proc_outcome_t::success) { + bool success = outcome == proc_outcome_t::success; + run_then(success); + } } - 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(); } + proc_status_t proc_state = proc_status_t::idle; +}; +/************************************************************************************** + * class: proc_t + * Manages the lifetime of a procedure of type T, including its alloc, launching, + * and reset back to "inactive" state once the procedure has been completed. + * The result of a procedure run is of type "proc_result_t". ResultType has + * to coincide with the type returned by the method "T::get_result()". + * There are three main ways to use the result of a procedure run: + * - "T::then(const proc_result_t&)" - method in T that runs on completion, and + * gets as argument the result of the run + * - "proc_t::get_future()" - returns a proc_future_t which the user can use + * directly to check the result of a run + * - "proc_t::then/then_always()" - provide dynamically a continuation task, for + * instance, by providing a lambda + * It uses a unique_ptr to allow the use of procedures that are forward declared. + ************************************************************************************/ + +// Implementation of the Procedure Manager functionality, including launching, trigger events, clearing +template +class proc_t : public proc_base_t +{ +public: + // cannot derive automatically this type + using result_type = ResultType; + using proc_result_type = proc_result_t; + using proc_future_type = proc_future_t; + using then_callback_list_t = callback_group_t; + using callback_t = typename then_callback_list_t::callback_t; + using callback_id_t = typename then_callback_list_t::callback_id_t; + + template + explicit proc_t(Args&&... args) : proc_ptr(new T(std::forward(args)...)) + { + static_assert(std::is_same()))>::value, + "The types \"proc_t::result_type\" and the return of T::get_result() have to match"); + } + + const T* get() const { return proc_ptr.get(); } + T* release() { return proc_ptr.release(); } + + //! method to handle external events. "T" must have the method "T::react(const Event&)" for the trigger to take effect template - void trigger_event(Event&& e) + void trigger(Event&& e) { - if (is_running()) { - proc_outcome_t outcome = proc_impl_ptr->trigger_event(std::forward(e)); + if (is_busy()) { + proc_outcome_t outcome = proc_ptr->react(std::forward(e)); handle_outcome(outcome); if (outcome == proc_outcome_t::repeat) { run(); @@ -211,87 +300,106 @@ public: } } + //! returns an object which the user can use to check if the procedure has ended. + proc_future_type get_future() + { + if (future_result == nullptr) { + future_result = std::make_shared(proc_result); + } + return proc_future_type{future_result}; + } + + //! methods to schedule continuation tasks + callback_id_t then(const callback_t& c) { return complete_callbacks.on_next_call(c); } + callback_id_t then_always(const callback_t& c) { return complete_callbacks.on_every_call(c); } + + //! launch a procedure, returning true if successful or running and false if it error or it failed to launch template bool launch(Args&&... args) { - if (is_active()) { - // if already active + if (is_busy()) { return false; } - proc_state = proc_state_t::on_going; - proc_outcome_t init_ret = proc_impl_ptr->init(std::forward(args)...); + proc_state = proc_base_t::proc_status_t::on_going; + proc_outcome_t init_ret = proc_ptr->init(std::forward(args)...); + handle_outcome(init_ret); switch (init_ret) { case proc_outcome_t::error: - handle_outcome(init_ret); - clear(); return false; - case proc_outcome_t::success: - handle_outcome(init_ret); - // does not reset, and returns true - break; case proc_outcome_t::repeat: run(); // call run right away break; - case proc_outcome_t::yield: + default: break; } return true; } - proc_result_t pop(); - - // on_complete interface - complete_callback_list_t::id_type then(const complete_callback_list_t::callback_t& c) - { - return complete_callbacks.call_once(c); - } - complete_callback_list_t::id_type then_always(const complete_callback_list_t::callback_t& c) - { - return complete_callbacks.call_always(c); - } - protected: - friend proc_result_t; - bool is_running() const { return proc_state == proc_state_t::on_going; } - void handle_outcome(proc_outcome_t outcome) + proc_outcome_t step() final { return proc_ptr->step(); } + + void run_then(bool is_success) final { - if (outcome == proc_outcome_t::error or outcome == proc_outcome_t::success) { - bool success = outcome == proc_outcome_t::success; - proc_state = success ? proc_state_t::success : proc_state_t::error; - detail::optional_complete(proc_impl_ptr.get(), success); - complete_callbacks.run(success); + // update result state + if (is_success) { + proc_result.extract_val(*proc_ptr); + } else { + proc_result.set_error(); } + // call T::then() if it exists + detail::optional_then(proc_ptr.get(), proc_result); + // signal continuations + complete_callbacks(proc_result); + // propagate proc_result to future if it exists, and release future + if (future_result != nullptr) { + *future_result = proc_result; + future_result.reset(); + } + // reset the current result, to prepare it for a new run. + proc_result.clear(); + // back to inactive + detail::optional_clear(proc_ptr.get()); + proc_state = proc_status_t::idle; } - proc_state_t proc_state = proc_state_t::inactive; - std::unique_ptr proc_impl_ptr; - complete_callback_list_t complete_callbacks; + std::unique_ptr proc_ptr; + proc_result_type proc_result; + std::shared_ptr future_result; //! used if get_future() itf is used. + then_callback_list_t complete_callbacks; }; -template -struct proc_result_t { - explicit proc_result_t(proc_t* parent_) : parent(parent_) {} - ~proc_result_t() +/************************************************************************************** + * class: event_handler_t + * Bundles several proc_managers together with same trigger(Args...) itf. + * Once trigger(...) is called, all registered proc_managers get triggered + * as well. + ************************************************************************************/ +// NOTE: Potential improvements: a method "trigger_during_this_run" that unregisters the handler +// once the procedure run is finished. +template +class event_handler_t +{ +public: + using callback_id_t = typename callback_group_t::callback_id_t; + + template + callback_id_t on_next_trigger(proc_t& p) { - if (parent->is_complete()) { - parent->clear(); - } + return callbacks.on_next_call([&p](EventType&& ev) { p.trigger(std::forward(ev)); }); } - 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(); } + + template + callback_id_t on_every_trigger(proc_t& p) + { + return callbacks.on_every_call([&p](EventType&& ev) { p.trigger(std::forward(ev)); }); + } + + void trigger(EventType&& ev) { callbacks(std::forward(ev)); } private: - proc_t* parent; + callback_group_t callbacks; }; -template -proc_result_t proc_t::pop() -{ - return proc_result_t{this}; -} - /************************************************************************************** * class: func_proc_t * A proc used to store lambda functions and other function pointers as a step() @@ -308,106 +416,52 @@ private: std::function step_func; }; -/************************************************************************************** - * class: query_proc_t - * A helper proc_impl_t whose step()/finally() are no op, but has a trigger_event() that - * signals that the method has finished and store a result of type OutcomeType. - ************************************************************************************/ -template -class query_proc_t -{ -public: - proc_outcome_t init() { return proc_outcome_t::yield; } - proc_outcome_t step() { return proc_outcome_t::yield; } - - proc_outcome_t trigger_event(const OutcomeType& outcome_) - { - outcome = outcome_; - return proc_outcome_t::success; - } - - const OutcomeType& result() const { return outcome; } - -private: - OutcomeType outcome; -}; - /************************************************************************************** * class: proc_manager_list_t * Stores procedure managers and, when run() is called, calls sequentially all * the stored procedures run() method, and removes the procedures if they have - * completed. - * There are different ways to add a procedure to the list: + * already completed. + * There are two ways to add a procedure to the list: * - add_proc(...) - adds a proc_t, and once the procedure has completed, takes it - * out of the container without resetting it back to its initial state - * or deleting. This is useful, if the user wants to extract the - * procedure result after it has been taken off the manager list. - * "proc" variable has to outlive its completion - * - consume_proc(...) - receives a proc_t as a rvalue, and calls the proc_t - * destructor once the procedure has ended. Useful, for procedures - * for which the user is not interested in the result, or reusing - * - defer_proc(...) - same as add_proc(...), but once the procedure has finished, it - * automatically sets the procedure back to its initial state. - * Useful if the user is not interested in handling the result - * - defer_task(...) - same as consume_proc(...) but takes a function pointer that - * specifies a proc_impl_t step() function + * out of the container. In case a r-value ref is passed, this class + * calls its destructor. + * - add_task(...) - same as add_proc(...) but takes a function pointer that + * specifies a proc_impl_t step() function ************************************************************************************/ class proc_manager_list_t { - using proc_deleter_t = std::function; - using proc_obj_t = std::unique_ptr; - - template - struct recycle_deleter_t { - void operator()(proc_manager_itf_t* p) - { - if (p != nullptr) { - T* Tp = static_cast(p); - Tp->clear(); - // just resets back to inactive, and does not dealloc - } - } - }; + using proc_deleter_t = std::function; + using proc_obj_t = std::unique_ptr; public: - template - void add_proc(proc_t& proc) + template + void add_proc(proc_t& proc) { - if (proc.is_complete()) { + if (proc.is_idle()) { return; } - proc_obj_t ptr(&proc, [](proc_manager_itf_t* p) { /* do nothing */ }); + proc_obj_t ptr(&proc, [](proc_base_t* p) { /* do nothing */ }); proc_list.push_back(std::move(ptr)); } - template - void consume_proc(proc_t&& proc) + // since it receives a r-value, it calls the default destructor + template + void add_proc(proc_t&& proc) { - if (proc.is_complete()) { + if (proc.is_idle()) { return; } - proc_obj_t ptr(new proc_t(std::move(proc)), std::default_delete()); + proc_obj_t ptr(new proc_t(std::move(proc)), std::default_delete()); proc_list.push_back(std::move(ptr)); } - template - void defer_proc(proc_t& proc) - { - if (proc.is_complete()) { - proc.clear(); - return; - } - proc_obj_t ptr(&proc, recycle_deleter_t >()); - proc_list.push_back(std::move(ptr)); - } - - bool defer_task(std::function step_func) + bool add_task(std::function step_func) { proc_t proc(std::move(step_func)); if (not proc.launch()) { return false; } - consume_proc(std::move(proc)); + add_proc(std::move(proc)); return true; } diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 82ff6caf1..6172e57a3 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -196,25 +196,26 @@ public: typedef enum { BARRING_NONE = 0, BARRING_MO_DATA, BARRING_MO_SIGNALLING, BARRING_MT, BARRING_ALL } barring_t; virtual void left_rrc_connected() = 0; virtual void set_barring(barring_t barring) = 0; - virtual void paging(srslte::s_tmsi_t* ue_identity) = 0; + virtual bool paging(srslte::s_tmsi_t* ue_identity) = 0; virtual bool is_attached() = 0; virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; virtual uint32_t get_k_enb_count() = 0; virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0; virtual uint32_t get_ipv4_addr() = 0; virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0; - virtual void plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) = 0; - virtual bool connection_request_completed(bool outcome) = 0; - virtual void run_tti(uint32_t tti) = 0; + virtual void + plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], + int nof_plmns) = 0; + virtual bool connection_request_completed(bool outcome) = 0; + virtual void run_tti(uint32_t tti) = 0; }; // NAS interface for UE class nas_interface_ue { public: - virtual void start_attach_request(srslte::proc_state_t* proc_result, srslte::establishment_cause_t cause_) = 0; - virtual bool detach_request(const bool switch_off) = 0; + virtual void start_attach_request(srslte::proc_result_t* proc_result, srslte::establishment_cause_t cause_) = 0; + virtual bool detach_request(const bool switch_off) = 0; }; // PDCP interface for RRC diff --git a/lib/test/common/stack_procedure_test.cc b/lib/test/common/stack_procedure_test.cc index 318ccf0fe..0a5abeb18 100644 --- a/lib/test/common/stack_procedure_test.cc +++ b/lib/test/common/stack_procedure_test.cc @@ -58,8 +58,9 @@ public: TestObj(const TestObj& other) { printf("TestObj copy ctor called: {%s,%d} <- {%s,%d}!!!\n", to_string(state), id, to_string(other.state), other.id); - id = other.id; - state = obj_state_t::copy_ctor; + id = other.id; + state = obj_state_t::copy_ctor; + counters = other.counters; copy_counter++; } TestObj(TestObj&& other) noexcept @@ -67,6 +68,7 @@ public: printf("TestObj move ctor called: {%s,%d} <- {%s,%d}!!!\n", to_string(state), id, to_string(other.state), other.id); id = other.id; state = obj_state_t::move_ctor; + counters = other.counters; other.state = obj_state_t::from_move_ctor; move_counter++; } @@ -82,8 +84,9 @@ public: id, to_string(other.state), other.id); - id = other.id; - state = other.state; + id = other.id; + state = other.state; + counters = other.counters; copy_counter++; return *this; } @@ -97,6 +100,7 @@ public: if (&other != this) { id = other.id; state = other.state; + counters = other.counters; other.state = obj_state_t::from_move_assign; move_counter++; } @@ -105,9 +109,14 @@ public: obj_state_t state = obj_state_t::default_ctor; int id = 0; - static int copy_counter; - static int move_counter; - static int dtor_counter; + struct stats_t { + int then_counter = 0; + int reset_counter = 0; + }; + mutable stats_t counters; + static int copy_counter; + static int move_counter; + static int dtor_counter; }; int TestObj::copy_counter = 0; @@ -132,8 +141,7 @@ public: printf("Failed to initiate custom_proc\n"); return proc_outcome_t::error; } - obj.id = a_; - reset_called = false; + obj.id = a_; return proc_outcome_t::yield; } proc_outcome_t step() @@ -143,13 +151,19 @@ public: } return proc_outcome_t::yield; } - void on_complete(bool is_success) { printf("TestObj %d stop() was called\n", obj.id); } + void then(const srslte::proc_result_t& result) const + { + printf("TestObj %d then() was called\n", obj.id); + obj.counters.then_counter++; + } + const char* name() const { return "custom proc"; } void clear() { reset_called = true; printf("TestObj was reset\n"); } + int get_result() const { return obj.id; } TestObj obj; const int ctor_value = 5; @@ -164,55 +178,65 @@ class custom_proc2_t public: proc_outcome_t init() { - exit_val = "init"; - counter = 0; + exit_val = "init"; + event_val = ""; + counter = 0; return proc_outcome_t::yield; } proc_outcome_t step() { if (counter++ > 5) { + exit_val = "success"; return proc_outcome_t::success; } return proc_outcome_t::yield; } - void on_complete(bool is_success) + // trigger itf + struct event_t { + std::string event_val; + }; + proc_outcome_t react(const event_t& event) { - if (is_success) { - exit_val = "success"; - } else { - exit_val = "fail"; - } + event_val = event.event_val; + return proc_outcome_t::yield; } - std::string exit_val = ""; - int counter = 0; + + std::string get_result() const { return exit_val; } + + std::string exit_val = ""; + std::string event_val = ""; + int counter = 0; }; +static_assert(std::is_same::result_type, int>::value, + "Failed derivation of result type"); +static_assert(std::is_same::result_type, std::string>::value, + "Failed derivation of result type"); + int test_local_1() { + /* + * Description: Test if a procedure is cleaned automatically after is lifetime has ended + */ new_test(); printf("\n--- Test %s ---\n", __func__); - srslte::proc_t proc; - TESTASSERT(not proc.is_active()); + srslte::proc_t proc; + TESTASSERT(proc.is_idle() and not proc.is_busy()) proc.launch(1); - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); - TESTASSERT(not proc.get()->reset_called); + TESTASSERT(not proc.is_idle() and proc.is_busy()) + TESTASSERT(not proc.get()->reset_called) while (proc.run()) { } - - TESTASSERT(proc.is_active()); - TESTASSERT(proc.is_complete()); + TESTASSERT(proc.is_idle() and not proc.is_busy()) + TESTASSERT(proc.get()->obj.counters.then_counter == 1) + TESTASSERT(proc.get()->reset_called) // Proc is ready to be reused const custom_proc& procobj = *proc.get(); - TESTASSERT(procobj.obj.id == 1); - TESTASSERT(proc.is_active()); - printf("clear() being called\n"); - proc.clear(); - TESTASSERT(not proc.is_active()); - TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused - TESTASSERT(proc.get()->ctor_value == 5); + TESTASSERT(procobj.obj.id == 1) + TESTASSERT(not proc.is_busy() and proc.is_idle()) + TESTASSERT(proc.get()->ctor_value == 5) printf("EXIT\n"); TESTASSERT(TestObj::copy_counter == 0); @@ -225,38 +249,34 @@ 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 goes out of scope + * - check if the proc is cleared automatically after it finished + * - check if the proc_future value is correctly updated + * - check if creating a new future does not affect previous one */ new_test(); printf("\n--- Test %s ---\n", __func__); - srslte::proc_manager_list_t callbacks; - srslte::proc_t proc; - TESTASSERT(not proc.is_active()); + srslte::proc_manager_list_t callbacks; + srslte::proc_t proc; + TESTASSERT(not proc.is_busy() and proc.is_idle()) - TESTASSERT(proc.launch(2)); + TESTASSERT(proc.launch(2)) callbacks.add_proc(proc); // We have to call pop() explicitly to take the result - TESTASSERT(callbacks.size() == 1); + TESTASSERT(callbacks.size() == 1) + srslte::proc_future_t proc_fut = proc.get_future(); while (callbacks.size() > 0) { - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); + TESTASSERT(not proc_fut.is_complete()) + TESTASSERT(proc.is_busy()) callbacks.run(); } - TESTASSERT(proc.is_active()); - TESTASSERT(proc.is_complete()); + TESTASSERT(proc.is_idle()); + TESTASSERT(proc_fut.is_success() and *proc_fut.value() == 2) + TESTASSERT(proc.get()->obj.id == 2) + TESTASSERT(proc.get()->obj.counters.then_counter == 1) + TESTASSERT(proc.get()->reset_called) // Proc is ready to be reused - TESTASSERT(proc.get()->obj.id == 2); - TESTASSERT(proc.is_active()); - { - printf("pop being called\n"); - srslte::proc_result_t ret = proc.pop(); - TESTASSERT(proc.is_active()); - TESTASSERT(ret.is_success()); - // proc::reset() is finally called - } - TESTASSERT(not proc.is_active()); - TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused + srslte::proc_future_t proc_fut2 = proc.get_future(); + TESTASSERT(not proc_fut2.is_complete() and proc_fut.is_complete()) printf("EXIT\n"); TESTASSERT(TestObj::copy_counter == 0); @@ -268,25 +288,25 @@ int test_callback_1() int test_callback_2() { /* - * Description: Test a procedure inserted in a manager list via "proc_manager_list_t::consume_proc(...)" + * Description: Test a procedure inserted in a manager list as an r-value * - check if the proc disappears automatically after it finished */ new_test(); printf("\n--- Test %s ---\n", __func__); - srslte::proc_manager_list_t callbacks; - srslte::proc_t proc; - TESTASSERT(not proc.is_active()); + srslte::proc_manager_list_t callbacks; + srslte::proc_t proc; + TESTASSERT(not proc.is_busy()); + srslte::proc_future_t fut = proc.get_future(); TESTASSERT(proc.launch(3)); - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); - callbacks.consume_proc(std::move(proc)); + TESTASSERT(proc.is_busy()); + callbacks.add_proc(std::move(proc)); TESTASSERT(callbacks.size() == 1); while (callbacks.size() > 0) { callbacks.run(); } - // since the proc was consumed, it is erased without the need for pop() + TESTASSERT(fut.is_success() and *fut.value() == 3) printf("EXIT\n"); TESTASSERT(TestObj::copy_counter == 0); @@ -296,42 +316,6 @@ int test_callback_2() } 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(); - printf("\n--- Test %s ---\n", __func__); - srslte::proc_manager_list_t callbacks; - srslte::proc_t proc; - TESTASSERT(not proc.is_active()); - - proc.launch(4); - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); - callbacks.defer_proc(proc); // we still have access to proc, but we do not need to call pop() - TESTASSERT(callbacks.size() == 1); - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); - - while (callbacks.size() > 0) { - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.is_complete()); - callbacks.run(); - } - TESTASSERT(not proc.is_active()); - TESTASSERT(not proc.is_complete()); - TESTASSERT(proc.get()->reset_called); // Proc is ready to be reused - - printf("EXIT\n"); - TESTASSERT(TestObj::copy_counter == 0); - TESTASSERT(TestObj::move_counter == 0); - TESTASSERT(TestObj::dtor_counter == 0); // handler not yet destructed - return 0; -} - -int test_callback_4() { /* * Description: Test for Lambda procedure types @@ -344,7 +328,7 @@ int test_callback_4() int* counter = new int(5); { - callbacks.defer_task([counter]() { + callbacks.add_task([counter]() { printf("current counter=%d\n", *counter); if (--(*counter) == 0) { return proc_outcome_t::success; @@ -357,30 +341,29 @@ int test_callback_4() callbacks.run(); } - // printf("counter=%d\n", counter); TESTASSERT(*counter == 0); delete counter; return 0; } -int test_callback_5() +int test_callback_4() { /* * 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 proc; + srslte::proc_manager_list_t callbacks; + srslte::proc_t proc; TESTASSERT(proc.launch(5)); while (proc.run()) { - TESTASSERT(proc.is_active()); + TESTASSERT(proc.is_busy()); } - TESTASSERT(proc.is_active()); - TESTASSERT(not proc.get()->reset_called); - TESTASSERT(proc.is_complete()); - callbacks.defer_proc(proc); + TESTASSERT(proc.is_idle()); + TESTASSERT(proc.get()->obj.counters.then_counter == 1) + TESTASSERT(proc.get()->reset_called); + callbacks.add_proc(proc); TESTASSERT(callbacks.size() == 0); // do not add finished callbacks return 0; @@ -389,47 +372,79 @@ int test_callback_5() int test_complete_callback_1() { /* - * Description: Test if on_complete() callbacks are correctly called + * Description: Test if then() callbacks are correctly called */ printf("\n--- Test %s ---\n", __func__); - srslte::proc_manager_list_t callbacks; - srslte::proc_t proc; + srslte::proc_manager_list_t callbacks; + srslte::proc_t proc; std::string run_result; - auto continuation_task = [&run_result](bool is_success) { run_result = is_success ? "SUCCESS" : "FAILURE"; }; - std::string results[] = {"", "SUCCESS", "", "SUCCESS", "SUCCESS", "SUCCESS"}; + auto continuation_task = [&run_result](const srslte::proc_result_t& e) { + run_result = e.is_success() ? "SUCCESS" : "FAILURE"; + }; + const std::string results[] = {"", "SUCCESS", "", "SUCCESS", "SUCCESS", "SUCCESS"}; for (uint32_t i = 0; i < 6; ++i) { run_result = ""; if (i == 1) { - TESTASSERT(proc.then(continuation_task) == 0); + TESTASSERT(proc.then(continuation_task) == 0) } else if (i == 3) { - TESTASSERT(proc.then_always(continuation_task) == 0); + TESTASSERT(proc.then_always(continuation_task) == 0) } + srslte::proc_future_t fut = proc.get_future(); TESTASSERT(proc.launch()); - TESTASSERT(proc.get()->exit_val == "init"); + TESTASSERT(proc.get()->exit_val == "init") while (proc.run()) { - TESTASSERT(proc.get()->exit_val == "init"); - TESTASSERT(proc.is_active()); + TESTASSERT(proc.get()->exit_val == "init") + TESTASSERT(proc.is_busy()) } - TESTASSERT(proc.is_active() and proc.is_complete()); - srslte::proc_result_t ret = proc.pop(); - TESTASSERT(ret.is_success() and ret.proc()->exit_val == "success"); + TESTASSERT(proc.is_idle() and proc.get()->exit_val == "success") + TESTASSERT(fut.is_success() and *fut.value() == "success") - TESTASSERT(run_result == results[i]); + TESTASSERT(run_result == results[i]) } return 0; } +int test_event_handler_1() +{ + /* + * Description: Test if event handler calls trigger for multiple procedures + */ + printf("\n--- Test %s ---\n", __func__); + srslte::proc_t proc, proc2; + srslte::event_handler_t ev_handler; + + TESTASSERT(proc.launch()) + TESTASSERT(proc2.launch()) + TESTASSERT(proc.is_busy() and proc2.is_busy()) + TESTASSERT(proc.get()->exit_val == "init" and proc2.get()->exit_val == "init") + TESTASSERT(proc.get()->event_val.empty() and proc2.get()->event_val.empty()) + + ev_handler.on_next_trigger(proc); + ev_handler.on_every_trigger(proc2); + + ev_handler.trigger(custom_proc2_t::event_t{"event1"}); + TESTASSERT(proc.get()->event_val == "event1" and proc.get()->event_val == "event1") + ev_handler.trigger(custom_proc2_t::event_t{"event2"}); + TESTASSERT(proc.get()->event_val == "event1" and proc2.get()->event_val == "event2") + + printf("Procedures correctly triggered by event handler\n"); + + return 0; +} + int main() { - TESTASSERT(test_local_1() == 0); - TESTASSERT(test_callback_1() == 0); - TESTASSERT(test_callback_2() == 0); - TESTASSERT(test_callback_3() == 0); - TESTASSERT(test_callback_4() == 0); - TESTASSERT(test_callback_5() == 0); - TESTASSERT(test_complete_callback_1() == 0); + TESTASSERT(test_local_1() == 0) + TESTASSERT(test_callback_1() == 0) + TESTASSERT(test_callback_2() == 0) + TESTASSERT(test_callback_3() == 0) + TESTASSERT(test_callback_4() == 0) + TESTASSERT(test_complete_callback_1() == 0) + TESTASSERT(test_event_handler_1() == 0) + + std::cout << "\n---------------\nResult: Success\n"; return 0; } diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index dc53874fb..b53a930ba 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -624,10 +624,10 @@ private: class process_pcch_proc; class go_idle_proc; class cell_reselection_proc; - srslte::proc_t cell_searcher; - srslte::proc_t si_acquirer; - srslte::proc_t serv_cell_cfg; - srslte::proc_t cell_selector; + srslte::proc_t cell_searcher; + srslte::proc_t si_acquirer; + srslte::proc_t serv_cell_cfg; + srslte::proc_t cell_selector; srslte::proc_t idle_setter; srslte::proc_t pcch_processor; srslte::proc_t conn_req_proc; diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index 66f268842..c80eaeeb6 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -41,9 +41,9 @@ public: explicit cell_search_proc(rrc* parent_); 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 react(const cell_search_event_t& event); - phy_interface_rrc_lte::cell_search_ret_t get_cs_ret() const { return search_result.cs_ret; } + phy_interface_rrc_lte::cell_search_ret_t get_result() const { return search_result.cs_ret; } static const char* name() { return "Cell Search"; } private: @@ -51,11 +51,11 @@ private: // conts rrc* rrc_ptr; - srslte::log* log_h; // state vars - cell_search_event_t search_result; - state_t state; + cell_search_event_t search_result; + srslte::proc_future_t si_acquire_fut; + state_t state; }; class rrc::si_acquire_proc @@ -99,17 +99,20 @@ private: // state variables enum class search_state_t { next_sib, si_acquire } search_state; - uint32_t req_idx = 0; + uint32_t req_idx = 0; + srslte::proc_future_t si_acquire_fut; }; class rrc::cell_selection_proc { public: + using cell_selection_complete_ev = srslte::proc_result_t; + explicit cell_selection_proc(rrc* parent_); srslte::proc_outcome_t init(); srslte::proc_outcome_t step(); - void on_complete(bool is_success); - cs_result_t get_cs_result() const { return cs_result; } + void then(const srslte::proc_result_t& proc_result) const; + cs_result_t get_result() const { return cs_result; } static const char* name() { return "Cell Selection"; } private: @@ -118,14 +121,15 @@ private: srslte::proc_outcome_t step_cell_config(); // consts - rrc* rrc_ptr; - srslte::log* log_h; + rrc* rrc_ptr; // state variables enum class search_state_t { cell_selection, cell_config, cell_search }; - cs_result_t cs_result; - search_state_t state; - uint32_t neigh_index; + cs_result_t cs_result; + search_state_t state; + uint32_t neigh_index; + srslte::proc_future_t cell_search_fut; + srslte::proc_future_t serv_cell_cfg_fut; }; class rrc::plmn_search_proc @@ -134,7 +138,7 @@ public: explicit plmn_search_proc(rrc* parent_); srslte::proc_outcome_t init(); srslte::proc_outcome_t step(); - void on_complete(bool is_success); + void then(const srslte::proc_result_t& result) const; static const char* name() { return "PLMN Search"; } private: @@ -143,24 +147,19 @@ private: srslte::log* log_h; // state variables - found_plmn_t found_plmns[MAX_FOUND_PLMNS]; - int nof_plmns = 0; + found_plmn_t found_plmns[MAX_FOUND_PLMNS]; + int nof_plmns = 0; + srslte::proc_future_t cell_search_fut; }; class rrc::connection_request_proc { public: - struct cell_selection_complete { - bool is_success; - cs_result_t cs_result; - }; - explicit connection_request_proc(rrc* parent_); - srslte::proc_outcome_t - init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t dedicated_info_nas_); + srslte::proc_outcome_t init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t dedicated_info_nas_); srslte::proc_outcome_t step(); - void on_complete(bool is_success); - srslte::proc_outcome_t trigger_event(const cell_selection_complete& e); + void then(const srslte::proc_result_t& result); + srslte::proc_outcome_t react(const cell_selection_proc::cell_selection_complete_ev& e); static const char* name() { return "Connection Request"; } private: @@ -173,7 +172,8 @@ private: // state variables enum class state_t { cell_selection, config_serving_cell, wait_t300 } state; - cs_result_t cs_ret; + cs_result_t cs_ret; + srslte::proc_future_t serv_cfg_fut; }; class rrc::process_pcch_proc @@ -186,7 +186,7 @@ public: explicit process_pcch_proc(rrc* parent_); 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 react(paging_complete e); static const char* name() { return "Process PCCH"; } private: @@ -198,6 +198,7 @@ private: // vars uint32_t paging_idx = 0; enum class state_t { next_record, nas_paging, serv_cell_cfg } state; + srslte::proc_future_t serv_cfg_fut; }; class rrc::go_idle_proc @@ -225,6 +226,8 @@ public: private: rrc* rrc_ptr; + + srslte::proc_future_t cell_selection_fut; }; } // namespace srsue diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index 9bcd62911..be11b32be 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -50,7 +50,7 @@ public: // RRC interface void left_rrc_connected(); - void paging(srslte::s_tmsi_t* ue_identity); + bool paging(srslte::s_tmsi_t* ue_identity); void set_barring(barring_t barring); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu); uint32_t get_k_enb_count(); @@ -60,13 +60,11 @@ public: bool get_ipv6_addr(uint8_t* ipv6_addr); // UE interface - void start_attach_request(srslte::proc_state_t* result, srslte::establishment_cause_t cause_) final; + void start_attach_request(srslte::proc_result_t* result, srslte::establishment_cause_t cause_) final; bool detach_request(const bool switch_off) final; - void plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) final; - bool start_connection_request(srslte::establishment_cause_t establish_cause, - srslte::unique_byte_buffer_t ded_info_nas); + void plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], + int nof_plmns) final; bool connection_request_completed(bool outcome) final; // timer callback @@ -261,6 +259,7 @@ private: class rrc_connect_proc { public: + using rrc_connect_complete_ev = srslte::proc_result_t; struct connection_request_completed_t { bool outcome; }; @@ -268,6 +267,8 @@ private: rrc_connect_proc(nas* nas_ptr_) : nas_ptr(nas_ptr_) {} srslte::proc_outcome_t init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t pdu); srslte::proc_outcome_t step(); + void then(const srslte::proc_result_t& result); + srslte::proc_outcome_t react(connection_request_completed_t event); static const char* name() { return "RRC Connect"; } private: @@ -281,7 +282,7 @@ private: struct plmn_search_complete_t { rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS]; int nof_plmns; - plmn_search_complete_t(rrc_interface_nas::found_plmn_t* plmns_, int nof_plmns_) : nof_plmns(nof_plmns_) + plmn_search_complete_t(const rrc_interface_nas::found_plmn_t* plmns_, int nof_plmns_) : nof_plmns(nof_plmns_) { if (nof_plmns > 0) { std::copy(&plmns_[0], &plmns_[nof_plmns], found_plmns); @@ -292,17 +293,18 @@ private: plmn_search_proc(nas* nas_ptr_) : nas_ptr(nas_ptr_) {} srslte::proc_outcome_t init(); srslte::proc_outcome_t step(); - srslte::proc_outcome_t trigger_event(const plmn_search_complete_t& t); + void then(const srslte::proc_result_t& result); + srslte::proc_outcome_t react(const plmn_search_complete_t& t); + srslte::proc_outcome_t react(const rrc_connect_proc::rrc_connect_complete_ev& t); static const char* name() { return "PLMN Search"; } private: nas* nas_ptr; enum class state_t { plmn_search, rrc_connect } state; }; - srslte::proc_manager_list_t callbacks; - srslte::proc_t plmn_searcher; - srslte::proc_t rrc_connector; - srslte::proc_t > conn_req_proc; + srslte::proc_manager_list_t callbacks; + srslte::proc_t plmn_searcher; + srslte::proc_t rrc_connector; }; } // namespace srsue diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index e33ca9ccc..99cd38aa0 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -316,7 +316,7 @@ bool rrc::plmn_search() rrc_log->error("Unable to initiate PLMN search\n"); return false; } - callback_list.defer_proc(plmn_searcher); + callback_list.add_proc(plmn_searcher); return true; } @@ -345,7 +345,7 @@ bool rrc::connection_request(srslte::establishment_cause_t cause, srslte::unique rrc_log->error("Failed to initiate connection request procedure\n"); return false; } - callback_list.defer_proc(conn_req_proc); + callback_list.add_proc(conn_req_proc); return true; } @@ -1189,7 +1189,7 @@ bool rrc::con_reconfig_ho(asn1::rrc::rrc_conn_recfg_s* reconfig) void rrc::start_ho() { - callback_list.defer_task([this]() { + callback_list.add_task([this]() { if (state != RRC_STATE_CONNECTED) { rrc_log->info("HO interrupted, since RRC is no longer in connected state\n"); return srslte::proc_outcome_t::success; @@ -1208,7 +1208,7 @@ void rrc::start_go_idle() rrc_log->info("Failed to set RRC to IDLE\n"); return; } - callback_list.defer_proc(idle_setter); + callback_list.add_proc(idle_setter); } // Handle RRC Reconfiguration without MobilityInformation Section 5.3.5.3 @@ -1478,7 +1478,7 @@ void rrc::start_cell_reselection() return; } - if (cell_reselector.is_active()) { + if (cell_reselector.is_busy()) { // it is already running return; } @@ -1492,7 +1492,7 @@ void rrc::start_cell_reselection() void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret, const phy_interface_rrc_lte::phy_cell_t& found_cell) { - cell_searcher.trigger_event(cell_search_proc::cell_search_event_t{cs_ret, found_cell}); + cell_searcher.trigger(cell_search_proc::cell_search_event_t{cs_ret, found_cell}); } /******************************************************************************* @@ -1725,7 +1725,7 @@ void rrc::write_pdu_pcch(unique_byte_buffer_t pdu) void rrc::paging_completed(bool outcome) { - pcch_processor.trigger_event(process_pcch_proc::paging_complete{outcome}); + pcch_processor.trigger(process_pcch_proc::paging_complete{outcome}); } void rrc::process_pcch(unique_byte_buffer_t pdu) @@ -1760,7 +1760,7 @@ void rrc::process_pcch(unique_byte_buffer_t pdu) } // we do not care about the outcome - callback_list.defer_proc(pcch_processor); + callback_list.add_proc(pcch_processor); } void rrc::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index af0ab39aa..da9b9d532 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -35,7 +35,7 @@ using srslte::proc_outcome_t; * Cell Search Procedure *************************************/ -rrc::cell_search_proc::cell_search_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {} +rrc::cell_search_proc::cell_search_proc(rrc* parent_) : rrc_ptr(parent_) {} /* Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet */ proc_outcome_t rrc::cell_search_proc::init() @@ -43,7 +43,7 @@ proc_outcome_t rrc::cell_search_proc::init() Info("Starting...\n"); state = state_t::phy_cell_search; rrc_ptr->stack->start_cell_search(); - return proc_outcome_t::repeat; + return proc_outcome_t::yield; } /* Implements the SI acquisition procedure. Configures MAC/PHY scheduling to retrieve SI messages.*/ @@ -53,18 +53,15 @@ proc_outcome_t rrc::cell_search_proc::step() // Waits for cell search to complete return proc_outcome_t::yield; } else if (state == state_t::si_acquire) { - if (not rrc_ptr->si_acquirer.run()) { - // SI Acquire has completed - srslte::proc_result_t ret = rrc_ptr->si_acquirer.pop(); - if (ret.is_error()) { - Error("Failed to trigger SI acquire for SIB0\n"); - return proc_outcome_t::error; - } else { - // if(parent->serving_cell->has_sib(0)) { - // } - return proc_outcome_t::success; - } + if (rrc_ptr->si_acquirer.run()) { + return proc_outcome_t::yield; } + // SI Acquire has completed + if (si_acquire_fut.is_error()) { + Error("Failed to trigger SI acquire for SIB0\n"); + return proc_outcome_t::error; + } + return proc_outcome_t::success; } return proc_outcome_t::yield; } @@ -82,7 +79,7 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ rrc_ptr->set_serving_cell(new_cell); if (not rrc_ptr->phy->cell_is_camping()) { - log_h->warning("Could not camp on found cell.\n"); + Warning("Could not camp on found cell.\n"); return proc_outcome_t::error; } @@ -97,6 +94,7 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ Error("SI Acquire is already running...\n"); return proc_outcome_t::error; } + si_acquire_fut = rrc_ptr->si_acquirer.get_future(); // instruct MAC to look for SIB1 Info("Cell has no SIB1. Obtaining SIB1...\n"); @@ -104,7 +102,7 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ return proc_outcome_t::repeat; } -proc_outcome_t rrc::cell_search_proc::trigger_event(const cell_search_event_t& event) +proc_outcome_t rrc::cell_search_proc::react(const cell_search_event_t& event) { if (state != state_t::phy_cell_search) { Error("Received unexpected cell search result\n"); @@ -279,7 +277,8 @@ proc_outcome_t rrc::serving_cell_config_proc::step() Error("SI Acquire is already running...\n"); return proc_outcome_t::error; } - search_state = search_state_t::si_acquire; + si_acquire_fut = rrc_ptr->si_acquirer.get_future(); + search_state = search_state_t::si_acquire; return proc_outcome_t::repeat; } else { // UE had SIB already. Handle its SIB @@ -301,20 +300,20 @@ proc_outcome_t rrc::serving_cell_config_proc::step() return proc_outcome_t::success; } } else if (search_state == search_state_t::si_acquire) { - uint32_t required_sib = required_sibs[req_idx]; - if (not rrc_ptr->si_acquirer.run()) { - srslte::proc_result_t ret = rrc_ptr->si_acquirer.pop(); - if (ret.is_error() or not rrc_ptr->serving_cell->has_sib(required_sib)) { - if (required_sib < 2) { - log_h->warning("Serving Cell Configuration has failed\n"); - return proc_outcome_t::error; - } - } - // continue with remaining SIBs - search_state = search_state_t::next_sib; - req_idx++; - return proc_outcome_t::repeat; + if (rrc_ptr->si_acquirer.run()) { + return proc_outcome_t::yield; } + uint32_t required_sib = required_sibs[req_idx]; + if (si_acquire_fut.is_error() or not rrc_ptr->serving_cell->has_sib(required_sib)) { + if (required_sib < 2) { + log_h->warning("Serving Cell Configuration has failed\n"); + return proc_outcome_t::error; + } + } + // continue with remaining SIBs + search_state = search_state_t::next_sib; + req_idx++; + return proc_outcome_t::repeat; } return proc_outcome_t::yield; } @@ -323,7 +322,7 @@ proc_outcome_t rrc::serving_cell_config_proc::step() * Cell Selection Procedure *************************************/ -rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_), log_h(parent_->rrc_log) {} +rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_) {} /* * Cell selection procedure 36.304 5.2.3 @@ -361,14 +360,15 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection() // Try to select Cell rrc_ptr->set_serving_cell(rrc_ptr->neighbour_cells.at(neigh_index)->phy_cell); Info("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str()); - log_h->console("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str()); + rrc_ptr->rrc_log->console("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str()); /* BLOCKING CALL */ if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) { if (not rrc_ptr->serv_cell_cfg.launch(rrc_ptr->ue_required_sibs)) { return proc_outcome_t::error; } - state = search_state_t::cell_config; + serv_cell_cfg_fut = rrc_ptr->serv_cell_cfg.get_future(); + state = search_state_t::cell_config; return proc_outcome_t::repeat; } else { rrc_ptr->serving_cell->in_sync = false; @@ -400,27 +400,25 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection() if (not rrc_ptr->cell_searcher.launch()) { return proc_outcome_t::error; } - state = search_state_t::cell_search; + cell_search_fut = rrc_ptr->cell_searcher.get_future(); + state = search_state_t::cell_search; return proc_outcome_t::repeat; } proc_outcome_t rrc::cell_selection_proc::step_cell_search() { - if (rrc_ptr->cell_searcher.run()) { return proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->cell_searcher.pop(); - if (ret.is_error()) { + if (cell_search_fut.is_error()) { cs_result = cs_result_t::no_cell; return proc_outcome_t::error; - } else { - 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::no_cell; - Info("Cell Search of cell selection run successfully\n"); - return proc_outcome_t::success; } + cs_result = (cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) + ? cs_result_t::changed_cell + : cs_result_t::no_cell; + Info("Cell Search of cell selection run successfully\n"); + return proc_outcome_t::success; } proc_outcome_t rrc::cell_selection_proc::step_cell_config() @@ -428,18 +426,16 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_config() if (rrc_ptr->serv_cell_cfg.run()) { return proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->serv_cell_cfg.pop(); - if (ret.is_success()) { + if (serv_cell_cfg_fut.is_success()) { Info("All SIBs of serving cell obtained successfully\n"); cs_result = cs_result_t::changed_cell; return proc_outcome_t::success; - } else { - Error("While configuring serving cell\n"); - // resume cell selection - state = search_state_t::cell_selection; - ++neigh_index; - return proc_outcome_t::repeat; } + Error("While configuring serving cell\n"); + // resume cell selection + state = search_state_t::cell_selection; + ++neigh_index; + return proc_outcome_t::repeat; } proc_outcome_t rrc::cell_selection_proc::step() @@ -455,13 +451,13 @@ proc_outcome_t rrc::cell_selection_proc::step() return proc_outcome_t::error; } -void rrc::cell_selection_proc::on_complete(bool is_success) +void rrc::cell_selection_proc::then(const srslte::proc_result_t& proc_result) const { // Inform Connection Request Procedure Info("Completed with %s. Informing proc %s\n", - is_success ? "success" : "failure", + proc_result.is_success() ? "success" : "failure", 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(proc_result); } /************************************** @@ -478,6 +474,7 @@ proc_outcome_t rrc::plmn_search_proc::init() Error("Failed due to fail to init cell search...\n"); return proc_outcome_t::error; } + cell_search_fut = rrc_ptr->cell_searcher.get_future(); return proc_outcome_t::repeat; } @@ -492,16 +489,14 @@ proc_outcome_t rrc::plmn_search_proc::step() // wait for new TTI return proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->cell_searcher.pop(); - 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 (cell_search_fut.is_error() or cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) { // stop search nof_plmns = -1; Error("Failed due to failed cell search sub-procedure\n"); return proc_outcome_t::error; } - if (cs_ret.found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) { + if (cell_search_fut.value()->found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) { if (rrc_ptr->serving_cell->has_sib1()) { // Save PLMN and TAC to NAS for (uint32_t i = 0; i < rrc_ptr->serving_cell->nof_plmns(); i++) { @@ -518,7 +513,7 @@ proc_outcome_t rrc::plmn_search_proc::step() } } - if (cs_ret.last_freq == phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS) { + if (cell_search_fut.value()->last_freq == phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS) { Info("completed PLMN search\n"); return proc_outcome_t::success; } @@ -532,10 +527,10 @@ proc_outcome_t rrc::plmn_search_proc::step() return proc_outcome_t::repeat; } -void rrc::plmn_search_proc::on_complete(bool is_success) +void rrc::plmn_search_proc::then(const srslte::proc_result_t& result) const { // on cleanup, call plmn_search_completed - if (is_success) { + if (result.is_success()) { Info("completed with success\n"); rrc_ptr->nas->plmn_search_completed(found_plmns, nof_plmns); } else { @@ -577,25 +572,15 @@ proc_outcome_t rrc::connection_request_proc::init(srslte::establishment_cause_t cs_ret = cs_result_t::no_cell; state = state_t::cell_selection; - if (not rrc_ptr->cell_selector.launch()) { - if (not rrc_ptr->cell_selector.is_active()) { - // Launch failed but cell selection was not already running + if (rrc_ptr->cell_selector.is_idle()) { + // No one is running cell selection + if (not rrc_ptr->cell_selector.launch()) { Error("Failed to initiate cell selection procedure...\n"); return proc_outcome_t::error; - } else if (not rrc_ptr->cell_selector.is_complete()) { - // In case it was already running, just wait for an cell_selection_complete event trigger - Info("Cell selection proc already on-going. Wait for its result\n"); - } else { - // 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"); - cell_selection_complete e{}; - 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); } + rrc_ptr->callback_list.add_proc(rrc_ptr->cell_selector); } else { - // In case we were able to launch it, let the callback list handle it - rrc_ptr->callback_list.defer_proc(rrc_ptr->cell_selector); + Info("Cell selection proc already on-going. Wait for its result\n"); } return proc_outcome_t::yield; } @@ -609,9 +594,7 @@ proc_outcome_t rrc::connection_request_proc::step() if (rrc_ptr->serv_cell_cfg.run()) { return proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->serv_cell_cfg.pop(); - - if (ret.is_error()) { + if (serv_cfg_fut.is_error()) { Error("Configuring serving cell\n"); return proc_outcome_t::error; } @@ -643,13 +626,13 @@ proc_outcome_t rrc::connection_request_proc::step() return proc_outcome_t::success; } else if (rrc_ptr->timers->get(rrc_ptr->t300)->is_expired()) { // T300 is expired: 5.3.3.6 - Info("Timer T300 expired: ConnectionRequest timed out\n"); + Warning("Timer T300 expired: ConnectionRequest timed out\n"); rrc_ptr->mac->reset(); rrc_ptr->set_mac_default(); rrc_ptr->rlc->reestablish(); } else { // T300 is stopped but RRC not Connected is because received Reject: Section 5.3.3.8 - Info("Timer T300 stopped: Received ConnectionReject\n"); + Warning("Timer T300 stopped: Received ConnectionReject\n"); rrc_ptr->mac->reset(); rrc_ptr->set_mac_default(); } @@ -658,28 +641,27 @@ proc_outcome_t rrc::connection_request_proc::step() return proc_outcome_t::error; } -void rrc::connection_request_proc::on_complete(bool is_success) +void rrc::connection_request_proc::then(const srslte::proc_result_t& result) { - if (not is_success) { + if (result.is_error()) { log_h->warning("Could not establish connection. Deallocating dedicatedInfoNAS PDU\n"); this->dedicated_info_nas.reset(); - rrc_ptr->nas->connection_request_completed(false); } else { Info("Finished connection request procedure successfully.\n"); - rrc_ptr->nas->connection_request_completed(true); } + rrc_ptr->nas->connection_request_completed(result.is_success()); } -srslte::proc_outcome_t rrc::connection_request_proc::trigger_event(const cell_selection_complete& e) +srslte::proc_outcome_t rrc::connection_request_proc::react(const cell_selection_proc::cell_selection_complete_ev& e) { if (state != state_t::cell_selection) { // ignore if we are not expecting an cell selection result return proc_outcome_t::yield; } - if (not e.is_success) { + if (e.is_error()) { return proc_outcome_t::error; } - cs_ret = e.cs_result; + cs_ret = *e.value(); // .. and SI acquisition if (rrc_ptr->phy->cell_is_camping()) { @@ -695,7 +677,8 @@ srslte::proc_outcome_t rrc::connection_request_proc::trigger_event(const cell_se Error("Attach request failed to configure serving cell...\n"); return proc_outcome_t::error; } - state = state_t::config_serving_cell; + serv_cfg_fut = rrc_ptr->serv_cell_cfg.get_future(); + state = state_t::config_serving_cell; return proc_outcome_t::repeat; } else { switch (cs_ret) { @@ -744,11 +727,14 @@ proc_outcome_t rrc::process_pcch_proc::step() if (RRC_STATE_IDLE == rrc_ptr->state) { Info("S-TMSI match in paging message\n"); log_h->console("S-TMSI match in paging message\n"); - rrc_ptr->nas->paging(&s_tmsi_paged); + if (not rrc_ptr->nas->paging(&s_tmsi_paged)) { + Error("Unable to start NAS paging proc\n"); + return proc_outcome_t::error; + } state = state_t::nas_paging; return proc_outcome_t::repeat; } else { - log_h->warning("Received paging while in CONNECT\n"); + Warning("Received paging while in CONNECT\n"); } } else { Info("Received paging for unknown identity\n"); @@ -764,6 +750,7 @@ proc_outcome_t rrc::process_pcch_proc::step() Error("Failed to initiate a serving cell configuration procedure\n"); return proc_outcome_t::error; } + serv_cfg_fut = rrc_ptr->serv_cell_cfg.get_future(); } else { Info("Completed successfully\n"); return proc_outcome_t::success; @@ -777,8 +764,7 @@ proc_outcome_t rrc::process_pcch_proc::step() if (rrc_ptr->serv_cell_cfg.run()) { return proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->serv_cell_cfg.pop(); - if (ret.is_success()) { + if (serv_cfg_fut.is_success()) { Info("All SIBs of serving cell obtained successfully\n"); return proc_outcome_t::success; } else { @@ -789,8 +775,12 @@ proc_outcome_t rrc::process_pcch_proc::step() return proc_outcome_t::yield; } -proc_outcome_t rrc::process_pcch_proc::trigger_event(paging_complete e) +proc_outcome_t rrc::process_pcch_proc::react(paging_complete e) { + if (state != state_t::nas_paging) { + Warning("Received an unexpected paging complete\n"); + return proc_outcome_t::yield; + } if (not e.outcome) { Info("NAS Paging has failed\n"); return proc_outcome_t::error; @@ -826,8 +816,7 @@ proc_outcome_t rrc::go_idle_proc::step() rrc_ptr->leave_connected(); return proc_outcome_t::success; } else { - rrc_ptr->rrc_log->debug( - "Postponing transition to RRC IDLE (%d ms < %d ms)\n", rlc_flush_counter, rlc_flush_timeout); + Debug("Postponing transition to RRC IDLE (%d ms < %d ms)\n", rlc_flush_counter, rlc_flush_timeout); } return proc_outcome_t::yield; } @@ -846,6 +835,7 @@ proc_outcome_t rrc::cell_reselection_proc::init() Error("Failed to initiate a Cell Selection procedure...\n"); return proc_outcome_t::error; } + cell_selection_fut = rrc_ptr->cell_selector.get_future(); return proc_outcome_t::yield; } @@ -855,13 +845,12 @@ proc_outcome_t rrc::cell_reselection_proc::step() if (rrc_ptr->cell_selector.run()) { return srslte::proc_outcome_t::yield; } - srslte::proc_result_t ret = rrc_ptr->cell_selector.pop(); - if (ret.is_error()) { + if (cell_selection_fut.is_error()) { Error("Cell Reselection - Error while selecting a cell\n"); return srslte::proc_outcome_t::error; } - switch (ret.proc()->get_cs_result()) { + switch (*cell_selection_fut.value()) { case cs_result_t::changed_cell: // New cell has been selected, start receiving PCCH rrc_ptr->mac->pcch_start_rx(); diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index d4ac62765..50965cfec 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -59,21 +59,34 @@ proc_outcome_t nas::plmn_search_proc::init() proc_outcome_t nas::plmn_search_proc::step() { - if (state == state_t::rrc_connect) { - if (nas_ptr->rrc_connector.run()) { - return proc_outcome_t::yield; - } - proc_result_t ret = nas_ptr->rrc_connector.pop(); - if (ret.is_success()) { - return proc_outcome_t::success; - } - nas_ptr->enter_emm_deregistered(); - return proc_outcome_t::error; - } return proc_outcome_t::yield; } -proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t& t) +void nas::plmn_search_proc::then(const srslte::proc_result_t& result) +{ + ProcInfo("Completed with %s\n", result.is_success() ? "success" : "failure"); + + // start T3411 + nas_ptr->nas_log->debug("Starting T3411\n"); + nas_ptr->timers->get(nas_ptr->t3411)->reset(); + nas_ptr->timers->get(nas_ptr->t3411)->run(); + + if (result.is_error()) { + nas_ptr->enter_emm_deregistered(); + } +} + +proc_outcome_t nas::plmn_search_proc::react(const rrc_connect_proc::rrc_connect_complete_ev& t) +{ + if (state != state_t::rrc_connect) { + // not expecting a rrc connection result + ProcWarning("Received unexpected RRC Connection Result event\n"); + return proc_outcome_t::yield; + } + return t.is_success() ? proc_outcome_t::success : proc_outcome_t::error; +} + +proc_outcome_t nas::plmn_search_proc::react(const plmn_search_complete_t& t) { if (state != state_t::plmn_search) { ProcWarning("PLMN Search Complete was received but PLMN Search is not running.\n"); @@ -114,12 +127,13 @@ proc_outcome_t nas::plmn_search_proc::trigger_event(const plmn_search_complete_t nas_ptr->rrc->plmn_select(nas_ptr->current_plmn); + state = state_t::rrc_connect; if (not nas_ptr->rrc_connector.launch(srslte::establishment_cause_t::mo_data, nullptr)) { ProcError("Unable to initiate RRC connection.\n"); return proc_outcome_t::error; } + nas_ptr->callbacks.add_proc(nas_ptr->rrc_connector); - state = state_t::rrc_connect; return proc_outcome_t::yield; } @@ -155,50 +169,56 @@ proc_outcome_t nas::rrc_connect_proc::init(srslte::establishment_cause_t cause_, ProcInfo("Starting...\n"); state = state_t::conn_req; - if (not nas_ptr->start_connection_request(cause_, std::move(pdu))) { + if (not nas_ptr->rrc->connection_request(cause_, std::move(pdu))) { + ProcError("Failed to initiate a connection request procedure\n"); return proc_outcome_t::error; } - return proc_outcome_t::yield; } proc_outcome_t nas::rrc_connect_proc::step() { - if (state == state_t::conn_req) { - if (nas_ptr->conn_req_proc.run()) { - return proc_outcome_t::yield; - } - proc_result_t> ret = nas_ptr->conn_req_proc.pop(); - if (ret.is_error()) { - ProcError("Could not establish RRC connection\n"); - return proc_outcome_t::error; - } + if (state != state_t::wait_attach) { + return proc_outcome_t::yield; + } + wait_timeout++; + // Wait until attachment. If doing a service request is already attached + if (wait_timeout < 5000 and nas_ptr->state != EMM_STATE_REGISTERED and nas_ptr->running and + nas_ptr->rrc->is_connected()) { + return proc_outcome_t::yield; + } + if (nas_ptr->state == EMM_STATE_REGISTERED) { + ProcInfo("Success: EMM Registered correctly.\n"); + return proc_outcome_t::success; + } else if (nas_ptr->state == EMM_STATE_DEREGISTERED) { + ProcError("Timeout or received attach reject while trying to attach\n"); + nas_ptr->nas_log->console("Failed to Attach\n"); + } else if (!nas_ptr->rrc->is_connected()) { + ProcError("Was disconnected while attaching\n"); + } else { + ProcError("Timed out while trying to attach\n"); + } + return proc_outcome_t::error; +} + +void nas::rrc_connect_proc::then(const srslte::proc_result_t& result) +{ + nas_ptr->plmn_searcher.trigger(result); +} + +proc_outcome_t nas::rrc_connect_proc::react(nas::rrc_connect_proc::connection_request_completed_t event) +{ + if (state == state_t::conn_req and event.outcome) { ProcInfo("Connection established correctly. Waiting for Attach\n"); wait_timeout = 0; // Wait until attachment. If doing a service request is already attached state = state_t::wait_attach; + // wake up proc return proc_outcome_t::repeat; + } else { + ProcError("Could not establish RRC connection\n"); + return proc_outcome_t::error; } - if (state == state_t::wait_attach) { - wait_timeout++; - // Wait until attachment. If doing a service request is already attached - if (wait_timeout >= 5000 or nas_ptr->state == EMM_STATE_REGISTERED or not nas_ptr->running or - not nas_ptr->rrc->is_connected()) { - if (nas_ptr->state == EMM_STATE_REGISTERED) { - ProcInfo("EMM Registered correctly\n"); - return proc_outcome_t::success; - } else if (nas_ptr->state == EMM_STATE_DEREGISTERED) { - ProcError("Timeout or received attach reject while trying to attach\n"); - nas_ptr->nas_log->console("Failed to Attach\n"); - } else if (!nas_ptr->rrc->is_connected()){ - ProcError("Was disconnected while attaching\n"); - } else { - ProcError("Timed out while trying to attach\n"); - } - return proc_outcome_t::error; - } - } - return proc_outcome_t::yield; } /********************************************************************* @@ -318,7 +338,7 @@ void nas::timer_expired(uint32_t timeout_id) * The function returns true if the UE could attach correctly or false in case of error or timeout during attachment. * */ -void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishment_cause_t cause_) +void nas::start_attach_request(srslte::proc_result_t* result, srslte::establishment_cause_t cause_) { nas_log->info("Attach Request\n"); switch (state) { @@ -341,29 +361,20 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme nas_log->info("No PLMN selected. Starting PLMN Search...\n"); if (not plmn_searcher.launch()) { if (result != nullptr) { - *result = proc_state_t::error; + result->set_error(); } return; } - callbacks.defer_proc(plmn_searcher); - plmn_searcher.then([this, result](bool is_success) { - nas_log->info("Attach Request from PLMN Search %s\n", is_success ? "finished successfully" : "failed"); + plmn_searcher.then([this, result](const proc_result_t& res) { + nas_log->info("Attach Request from PLMN Search %s\n", res.is_success() ? "finished successfully" : "failed"); if (result != nullptr) { - *result = is_success ? proc_state_t::success : proc_state_t::error; - } - // start T3411 - nas_log->debug("Starting T3411\n"); - timers->get(t3411)->reset(); - timers->get(t3411)->run(); - - if (not is_success) { - enter_emm_deregistered(); + *result = res; } }); } else { nas_log->error("PLMN selected in state %s\n", emm_state_text[state]); if (result != nullptr) { - *result = proc_state_t::error; + result->set_error(); } } break; @@ -371,43 +382,42 @@ void nas::start_attach_request(srslte::proc_state_t* result, srslte::establishme if (rrc->is_connected()) { nas_log->info("NAS is already registered and RRC connected\n"); if (result != nullptr) { - *result = proc_state_t::success; + result->set_val(); } } else { nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n"); if (not rrc_connector.launch(cause_, nullptr)) { nas_log->error("Cannot initiate concurrent rrc connection procedures\n"); if (result != nullptr) { - *result = proc_state_t::error; + result->set_error(); } return; } - callbacks.defer_proc(rrc_connector); - rrc_connector.then([this, result](bool is_success) { - if (is_success) { + rrc_connector.then([this, result](const proc_result_t& res) { + if (res.is_success()) { nas_log->info("NAS attached successfully\n"); } else { nas_log->error("Could not attach from attach_request\n"); } if (result != nullptr) { - *result = is_success ? proc_state_t::success : proc_state_t::error; + *result = res; } - return proc_outcome_t::success; }); + callbacks.add_proc(rrc_connector); } break; default: nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); if (result != nullptr) { - *result = proc_state_t::error; + result->set_error(); } } } -void nas::plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) +void nas::plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], + int nof_plmns) { - plmn_searcher.trigger_event(plmn_search_proc::plmn_search_complete_t(found_plmns, nof_plmns)); + plmn_searcher.trigger(plmn_search_proc::plmn_search_complete_t(found_plmns, nof_plmns)); } bool nas::detach_request(const bool switch_off) @@ -447,58 +457,41 @@ bool nas::is_attached() return state == EMM_STATE_REGISTERED; } -void nas::paging(s_tmsi_t* ue_identity) +bool nas::paging(s_tmsi_t* ue_identity) { if (state == EMM_STATE_REGISTERED) { nas_log->info("Received paging: requesting RRC connection establishment\n"); - if (rrc_connector.is_active()) { - nas_log->error("Cannot initiate concurrent RRC connection establishment procedures\n"); - return; - } if (not rrc_connector.launch(srslte::establishment_cause_t::mt_access, nullptr)) { nas_log->error("Could not launch RRC Connect()\n"); - return; + return false; } // once completed, call paging complete - callbacks.defer_task([this]() { - if (rrc_connector.run()) { - return proc_outcome_t::yield; - } - bool success = rrc_connector.pop().is_success(); - rrc->paging_completed(success); + rrc_connector.then([this](proc_result_t outcome) { + rrc->paging_completed(outcome.is_success()); return proc_outcome_t::success; }); + callbacks.add_proc(rrc_connector); } else { nas_log->warning("Received paging while in state %s\n", emm_state_text[state]); - } -} - -void nas::set_barring(barring_t barring) { - current_barring = barring; -} - -bool nas::start_connection_request(srslte::establishment_cause_t establish_cause, - srslte::unique_byte_buffer_t ded_info_nas) -{ - if (not conn_req_proc.launch()) { - nas_log->error("Failed to initiate a connection request procedure\n"); - return false; - } - if (not rrc->connection_request(establish_cause, std::move(ded_info_nas))) { - nas_log->error("Failed to initiate a connection request procedure\n"); - conn_req_proc.pop(); return false; } return true; } -bool nas::connection_request_completed(bool outcome) +void nas::set_barring(barring_t barring) { - conn_req_proc.trigger_event(outcome); - return conn_req_proc.is_active(); + current_barring = barring; } -void nas::select_plmn() { +// Signal from RRC that connection request proc completed +bool nas::connection_request_completed(bool outcome) +{ + rrc_connector.trigger(rrc_connect_proc::connection_request_completed_t{outcome}); + return true; +} + +void nas::select_plmn() +{ plmn_is_selected = false; @@ -1786,7 +1779,7 @@ void nas::send_detach_request(bool switch_off) if (not rrc_connector.launch(establishment_cause_t::mo_sig, std::move(pdu))) { nas_log->error("Failed to initiate RRC Connection Request\n"); } - callbacks.defer_proc(rrc_connector); + callbacks.add_proc(rrc_connector); } } diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 641bf91b0..e410f3337 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -119,10 +119,11 @@ public: printf("NAS generated SDU (len=%d):\n", sdu->N_bytes); last_sdu_len = sdu->N_bytes; srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes); + is_connected_flag = true; nas_ptr->connection_request_completed(true); return true; } - bool is_connected() {return false;} + bool is_connected() { return is_connected_flag; } uint16_t get_mcc() { return mcc; } uint16_t get_mnc() { return mnc; } @@ -132,8 +133,9 @@ public: private: nas* nas_ptr; - uint32_t last_sdu_len; + uint32_t last_sdu_len; found_plmn_t plmns; + bool is_connected_flag = false; }; class stack_dummy : public stack_interface_gw, public thread @@ -143,12 +145,12 @@ public: void init() { start(-1); } bool switch_on() final { - proc_state_t proc_result = proc_state_t::on_going; + proc_result_t proc_result; nas->start_attach_request(&proc_result, srslte::establishment_cause_t::mo_data); - while (proc_result == proc_state_t::on_going) { + while (not proc_result.is_complete()) { usleep(1000); } - return proc_result == proc_state_t::success; + return proc_result.is_success(); } void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) {