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