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 #ifndef BTIF_STATE_MACHINE_H
18 #define BTIF_STATE_MACHINE_H
19 
20 #include <map>
21 #include <utility>
22 
23 #include <base/logging.h>
24 
25 /**
26  * State machine used by BTIF components.
27  */
28 class BtifStateMachine {
29  public:
30   enum { kStateInvalid = -1 };
31 
32   /**
33    * A class to represent the state in the State Machine.
34    */
35   class State {
36     friend class BtifStateMachine;
37 
38    public:
39     /**
40      * Constructor.
41      *
42      * @param sm the State Machine to use
43      * @param state_id the unique State ID. It should be a non-negative number.
44      */
State(BtifStateMachine & sm,int state_id)45     State(BtifStateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
46 
47     virtual ~State() = default;
48 
49     /**
50      * Process an event.
51      * TODO: The arguments are wrong - used for backward compatibility.
52      * Will be replaced later.
53      *
54      * @param event the event type
55      * @param p_data the event data
56      * @return true if the processing was completed, otherwise false
57      */
58     virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;
59 
60     /**
61      * Get the State ID.
62      *
63      * @return the State ID
64      */
StateId()65     int StateId() const { return state_id_; }
66 
67    protected:
68     /**
69      * Called when a state is entered.
70      */
OnEnter()71     virtual void OnEnter() {}
72 
73     /**
74      * Called when a state is exited.
75      */
OnExit()76     virtual void OnExit() {}
77 
78     /**
79      * Transition the State Machine to a new state.
80      *
81      * @param dest_state_id the state ID to transition to. It must be one
82      * of the unique state IDs when the corresponding state was created.
83      */
TransitionTo(int dest_state_id)84     void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }
85 
86     /**
87      * Transition the State Machine to a new state.
88      *
89      * @param dest_state the state to transition to. It cannot be nullptr.
90      */
TransitionTo(BtifStateMachine::State * dest_state)91     void TransitionTo(BtifStateMachine::State* dest_state) {
92       sm_.TransitionTo(dest_state);
93     }
94 
95    private:
96     BtifStateMachine& sm_;
97     int state_id_;
98   };
99 
BtifStateMachine()100   BtifStateMachine()
101       : initial_state_(nullptr),
102         previous_state_(nullptr),
103         current_state_(nullptr) {}
~BtifStateMachine()104   ~BtifStateMachine() {
105     for (auto& kv : states_) delete kv.second;
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) return false;
153     return current_state_->ProcessEvent(event, p_data);
154   }
155 
156   /**
157    * Transition the State Machine to a new state.
158    *
159    * @param dest_state_id the state ID to transition to. It must be one
160    * of the unique state IDs when the corresponding state was created.
161    */
TransitionTo(int dest_state_id)162   void TransitionTo(int dest_state_id) {
163     auto it = states_.find(dest_state_id);
164 
165     CHECK(it != states_.end()) << "Unknown State ID: " << dest_state_id;
166     State* dest_state = it->second;
167     TransitionTo(dest_state);
168   }
169 
170   /**
171    * Transition the State Machine to a new state.
172    *
173    * @param dest_state the state to transition to. It cannot be nullptr.
174    */
TransitionTo(BtifStateMachine::State * dest_state)175   void TransitionTo(BtifStateMachine::State* dest_state) {
176     if (current_state_ != nullptr) {
177       current_state_->OnExit();
178     }
179     previous_state_ = current_state_;
180     current_state_ = dest_state;
181     current_state_->OnEnter();
182   }
183 
184   /**
185    * Add a state to the State Machine.
186    * The state machine takes ownership on the state - i.e., the state will
187    * be deleted by the State Machine itself.
188    *
189    * @param state the state to add
190    */
AddState(State * state)191   void AddState(State* state) {
192     states_.insert(std::make_pair(state->StateId(), state));
193   }
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 #endif  // BTIF_STATE_MACHINE_H
210