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 <bluetooth/log.h> 20 21 #include <map> 22 #include <utility> 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) { sm_.TransitionTo(dest_state); } 95 96 private: 97 StateMachine& sm_; 98 int state_id_; 99 }; 100 StateMachine()101 StateMachine() : initial_state_(nullptr), previous_state_(nullptr), current_state_(nullptr) {} ~StateMachine()102 ~StateMachine() { 103 for (auto& kv : states_) { 104 delete kv.second; 105 } 106 } 107 108 /** 109 * Start the State Machine operation. 110 */ Start()111 void Start() { TransitionTo(initial_state_); } 112 113 /** 114 * Quit the State Machine operation. 115 */ Quit()116 void Quit() { previous_state_ = current_state_ = nullptr; } 117 118 /** 119 * Get the current State ID. 120 * 121 * @return the current State ID 122 */ StateId()123 int StateId() const { 124 if (current_state_ != nullptr) { 125 return current_state_->StateId(); 126 } 127 return kStateInvalid; 128 } 129 130 /** 131 * Get the previous current State ID. 132 * 133 * @return the previous State ID 134 */ PreviousStateId()135 int PreviousStateId() const { 136 if (previous_state_ != nullptr) { 137 return previous_state_->StateId(); 138 } 139 return kStateInvalid; 140 } 141 142 /** 143 * Process an event. 144 * TODO: The arguments are wrong - used for backward compatibility. 145 * Will be replaced later. 146 * 147 * @param event the event type 148 * @param p_data the event data 149 * @return true if the processing was completed, otherwise false 150 */ ProcessEvent(uint32_t event,void * p_data)151 bool ProcessEvent(uint32_t event, void* p_data) { 152 if (current_state_ == nullptr) { 153 return false; 154 } 155 return current_state_->ProcessEvent(event, p_data); 156 } 157 158 /** 159 * Transition the State Machine to a new state. 160 * 161 * @param dest_state_id the state ID to transition to. It must be one 162 * of the unique state IDs when the corresponding state was created. 163 */ TransitionTo(int dest_state_id)164 void TransitionTo(int dest_state_id) { 165 auto it = states_.find(dest_state_id); 166 167 log::assert_that(it != states_.end(), "Unknown State ID: {}", dest_state_id); 168 State* dest_state = it->second; 169 TransitionTo(dest_state); 170 } 171 172 /** 173 * Transition the State Machine to a new state. 174 * 175 * @param dest_state the state to transition to. It cannot be nullptr. 176 */ TransitionTo(StateMachine::State * dest_state)177 void TransitionTo(StateMachine::State* dest_state) { 178 if (current_state_ != nullptr) { 179 current_state_->OnExit(); 180 } 181 previous_state_ = current_state_; 182 current_state_ = dest_state; 183 current_state_->OnEnter(); 184 } 185 186 /** 187 * Add a state to the State Machine. 188 * The state machine takes ownership on the state - i.e., the state will 189 * be deleted by the State Machine itself. 190 * 191 * @param state the state to add 192 */ AddState(State * state)193 void AddState(State* state) { states_.insert(std::make_pair(state->StateId(), state)); } 194 195 /** 196 * Set the initial state of the State Machine. 197 * 198 * @param initial_state the initial state 199 */ SetInitialState(State * initial_state)200 void SetInitialState(State* initial_state) { initial_state_ = initial_state; } 201 202 private: 203 State* initial_state_; 204 State* previous_state_; 205 State* current_state_; 206 std::map<int, State*> states_; 207 }; 208 209 } // namespace common 210 211 } // namespace bluetooth 212