You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
5.2 KiB
214 lines
5.2 KiB
/* |
|
* 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 <map> |
|
#include <utility> |
|
|
|
#include <base/logging.h> |
|
|
|
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<int, State*> states_; |
|
}; |
|
|
|
} // namespace common |
|
|
|
} // namespace bluetooth
|
|
|