1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <map> 20 #include <utility> 21 22 #include <base/logging.h> 23 24 namespace bluetooth { 25 26 namespace common { 27 28 /** 29 * State machine used by Bluetooth native stack. 30 */ 31 class StateMachine { 32 public: 33 enum { kStateInvalid = -1 }; 34 35 /** 36 * A class to represent the state in the State Machine. 37 */ 38 class State { 39 friend class StateMachine; 40 41 public: 42 /** 43 * Constructor. 44 * 45 * @param sm the State Machine to use 46 * @param state_id the unique State ID. It should be a non-negative number. 47 */ State(StateMachine & sm,int state_id)48 State(StateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {} 49 50 virtual ~State() = default; 51 52 /** 53 * Process an event. 54 * TODO: The arguments are wrong - used for backward compatibility. 55 * Will be replaced later. 56 * 57 * @param event the event type 58 * @param p_data the event data 59 * @return true if the processing was completed, otherwise false 60 */ 61 virtual bool ProcessEvent(uint32_t event, void* p_data) = 0; 62 63 /** 64 * Get the State ID. 65 * 66 * @return the State ID 67 */ StateId()68 int StateId() const { return state_id_; } 69 70 protected: 71 /** 72 * Called when a state is entered. 73 */ OnEnter()74 virtual void OnEnter() {} 75 76 /** 77 * Called when a state is exited. 78 */ OnExit()79 virtual void OnExit() {} 80 81 /** 82 * Transition the State Machine to a new state. 83 * 84 * @param dest_state_id the state ID to transition to. It must be one 85 * of the unique state IDs when the corresponding state was created. 86 */ TransitionTo(int dest_state_id)87 void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); } 88 89 /** 90 * Transition the State Machine to a new state. 91 * 92 * @param dest_state the state to transition to. It cannot be nullptr. 93 */ TransitionTo(StateMachine::State * dest_state)94 void TransitionTo(StateMachine::State* dest_state) { 95 sm_.TransitionTo(dest_state); 96 } 97 98 private: 99 StateMachine& sm_; 100 int state_id_; 101 }; 102 StateMachine()103 StateMachine() 104 : initial_state_(nullptr), 105 previous_state_(nullptr), 106 current_state_(nullptr) {} ~StateMachine()107 ~StateMachine() { 108 for (auto& kv : states_) delete kv.second; 109 } 110 111 /** 112 * Start the State Machine operation. 113 */ Start()114 void Start() { TransitionTo(initial_state_); } 115 116 /** 117 * Quit the State Machine operation. 118 */ Quit()119 void Quit() { previous_state_ = current_state_ = nullptr; } 120 121 /** 122 * Get the current State ID. 123 * 124 * @return the current State ID 125 */ StateId()126 int StateId() const { 127 if (current_state_ != nullptr) { 128 return current_state_->StateId(); 129 } 130 return kStateInvalid; 131 } 132 133 /** 134 * Get the previous current State ID. 135 * 136 * @return the previous State ID 137 */ PreviousStateId()138 int PreviousStateId() const { 139 if (previous_state_ != nullptr) { 140 return previous_state_->StateId(); 141 } 142 return kStateInvalid; 143 } 144 145 /** 146 * Process an event. 147 * TODO: The arguments are wrong - used for backward compatibility. 148 * Will be replaced later. 149 * 150 * @param event the event type 151 * @param p_data the event data 152 * @return true if the processing was completed, otherwise false 153 */ ProcessEvent(uint32_t event,void * p_data)154 bool ProcessEvent(uint32_t event, void* p_data) { 155 if (current_state_ == nullptr) return false; 156 return current_state_->ProcessEvent(event, p_data); 157 } 158 159 /** 160 * Transition the State Machine to a new state. 161 * 162 * @param dest_state_id the state ID to transition to. It must be one 163 * of the unique state IDs when the corresponding state was created. 164 */ TransitionTo(int dest_state_id)165 void TransitionTo(int dest_state_id) { 166 auto it = states_.find(dest_state_id); 167 168 CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id; 169 State* dest_state = it->second; 170 TransitionTo(dest_state); 171 } 172 173 /** 174 * Transition the State Machine to a new state. 175 * 176 * @param dest_state the state to transition to. It cannot be nullptr. 177 */ TransitionTo(StateMachine::State * dest_state)178 void TransitionTo(StateMachine::State* dest_state) { 179 if (current_state_ != nullptr) { 180 current_state_->OnExit(); 181 } 182 previous_state_ = current_state_; 183 current_state_ = dest_state; 184 current_state_->OnEnter(); 185 } 186 187 /** 188 * Add a state to the State Machine. 189 * The state machine takes ownership on the state - i.e., the state will 190 * be deleted by the State Machine itself. 191 * 192 * @param state the state to add 193 */ AddState(State * state)194 void AddState(State* state) { 195 states_.insert(std::make_pair(state->StateId(), state)); 196 } 197 198 /** 199 * Set the initial state of the State Machine. 200 * 201 * @param initial_state the initial state 202 */ SetInitialState(State * initial_state)203 void SetInitialState(State* initial_state) { initial_state_ = initial_state; } 204 205 private: 206 State* initial_state_; 207 State* previous_state_; 208 State* current_state_; 209 std::map<int, State*> states_; 210 }; 211 212 } // namespace common 213 214 } // namespace bluetooth 215