blob: 62d92d2636f2f4846adf103389de48d06b070968 [file] [log] [blame]
Pavlin Radoslavovd7522292017-11-24 19:12:11 -08001/*
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
Hansong Zhangdf14c992018-10-04 15:04:18 -070017#pragma once
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080018
19#include <map>
20#include <utility>
21
22#include <base/logging.h>
23
Hansong Zhangdf14c992018-10-04 15:04:18 -070024namespace bluetooth {
25
26namespace common {
27
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080028/**
Hansong Zhangdf14c992018-10-04 15:04:18 -070029 * State machine used by Bluetooth native stack.
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080030 */
Hansong Zhangdf14c992018-10-04 15:04:18 -070031class StateMachine {
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080032 public:
33 enum { kStateInvalid = -1 };
34
35 /**
36 * A class to represent the state in the State Machine.
37 */
38 class State {
Hansong Zhangdf14c992018-10-04 15:04:18 -070039 friend class StateMachine;
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080040
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 */
Hansong Zhangdf14c992018-10-04 15:04:18 -070048 State(StateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080049
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 */
68 int StateId() const { return state_id_; }
69
70 protected:
71 /**
72 * Called when a state is entered.
73 */
74 virtual void OnEnter() {}
75
76 /**
77 * Called when a state is exited.
78 */
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 */
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 */
Hansong Zhangdf14c992018-10-04 15:04:18 -070094 void TransitionTo(StateMachine::State* dest_state) {
Pavlin Radoslavovd7522292017-11-24 19:12:11 -080095 sm_.TransitionTo(dest_state);
96 }
97
98 private:
Hansong Zhangdf14c992018-10-04 15:04:18 -070099 StateMachine& sm_;
Pavlin Radoslavovd7522292017-11-24 19:12:11 -0800100 int state_id_;
101 };
102
Hansong Zhangdf14c992018-10-04 15:04:18 -0700103 StateMachine()
Pavlin Radoslavovd7522292017-11-24 19:12:11 -0800104 : initial_state_(nullptr),
105 previous_state_(nullptr),
106 current_state_(nullptr) {}
Hansong Zhangdf14c992018-10-04 15:04:18 -0700107 ~StateMachine() {
Pavlin Radoslavovd7522292017-11-24 19:12:11 -0800108 for (auto& kv : states_) delete kv.second;
109 }
110
111 /**
112 * Start the State Machine operation.
113 */
114 void Start() { TransitionTo(initial_state_); }
115
116 /**
117 * Quit the State Machine operation.
118 */
119 void Quit() { previous_state_ = current_state_ = nullptr; }
120
121 /**
122 * Get the current State ID.
123 *
124 * @return the current State ID
125 */
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 */
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 */
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 */
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 */
Hansong Zhangdf14c992018-10-04 15:04:18 -0700178 void TransitionTo(StateMachine::State* dest_state) {
Pavlin Radoslavovd7522292017-11-24 19:12:11 -0800179 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 */
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 */
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
Hansong Zhangdf14c992018-10-04 15:04:18 -0700212} // namespace common
213
214} // namespace bluetooth