/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include namespace bluetooth { namespace common { /** * State machine used by Bluetooth native stack. */ class StateMachine { public: enum { kStateInvalid = -1 }; /** * A class to represent the state in the State Machine. */ class State { friend class StateMachine; public: /** * Constructor. * * @param sm the State Machine to use * @param state_id the unique State ID. It should be a non-negative number. */ State(StateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {} virtual ~State() = default; /** * Process an event. * TODO: The arguments are wrong - used for backward compatibility. * Will be replaced later. * * @param event the event type * @param p_data the event data * @return true if the processing was completed, otherwise false */ virtual bool ProcessEvent(uint32_t event, void* p_data) = 0; /** * Get the State ID. * * @return the State ID */ int StateId() const { return state_id_; } protected: /** * Called when a state is entered. */ virtual void OnEnter() {} /** * Called when a state is exited. */ virtual void OnExit() {} /** * Transition the State Machine to a new state. * * @param dest_state_id the state ID to transition to. It must be one * of the unique state IDs when the corresponding state was created. */ void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); } /** * Transition the State Machine to a new state. * * @param dest_state the state to transition to. It cannot be nullptr. */ void TransitionTo(StateMachine::State* dest_state) { sm_.TransitionTo(dest_state); } private: StateMachine& sm_; int state_id_; }; StateMachine() : initial_state_(nullptr), previous_state_(nullptr), current_state_(nullptr) {} ~StateMachine() { for (auto& kv : states_) delete kv.second; } /** * Start the State Machine operation. */ void Start() { TransitionTo(initial_state_); } /** * Quit the State Machine operation. */ void Quit() { previous_state_ = current_state_ = nullptr; } /** * Get the current State ID. * * @return the current State ID */ int StateId() const { if (current_state_ != nullptr) { return current_state_->StateId(); } return kStateInvalid; } /** * Get the previous current State ID. * * @return the previous State ID */ int PreviousStateId() const { if (previous_state_ != nullptr) { return previous_state_->StateId(); } return kStateInvalid; } /** * Process an event. * TODO: The arguments are wrong - used for backward compatibility. * Will be replaced later. * * @param event the event type * @param p_data the event data * @return true if the processing was completed, otherwise false */ bool ProcessEvent(uint32_t event, void* p_data) { if (current_state_ == nullptr) return false; return current_state_->ProcessEvent(event, p_data); } /** * Transition the State Machine to a new state. * * @param dest_state_id the state ID to transition to. It must be one * of the unique state IDs when the corresponding state was created. */ void TransitionTo(int dest_state_id) { auto it = states_.find(dest_state_id); CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id; State* dest_state = it->second; TransitionTo(dest_state); } /** * Transition the State Machine to a new state. * * @param dest_state the state to transition to. It cannot be nullptr. */ void TransitionTo(StateMachine::State* dest_state) { if (current_state_ != nullptr) { current_state_->OnExit(); } previous_state_ = current_state_; current_state_ = dest_state; current_state_->OnEnter(); } /** * Add a state to the State Machine. * The state machine takes ownership on the state - i.e., the state will * be deleted by the State Machine itself. * * @param state the state to add */ void AddState(State* state) { states_.insert(std::make_pair(state->StateId(), state)); } /** * Set the initial state of the State Machine. * * @param initial_state the initial state */ void SetInitialState(State* initial_state) { initial_state_ = initial_state; } private: State* initial_state_; State* previous_state_; State* current_state_; std::map states_; }; } // namespace common } // namespace bluetooth