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