blob: d72c8f80bec26ef29b3748a8f8fb9f77fe7340fb [file] [log] [blame]
rkc122239752016-04-20 23:59:081// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
6
tommytad8462b2016-08-22 08:09:397#include "base/bind.h"
8#include "base/location.h"
9#include "base/single_thread_task_runner.h"
10#include "base/threading/thread_task_runner_handle.h"
11#include "device/bluetooth/bluetooth_gatt_notify_session.h"
rkc122239752016-04-20 23:59:0812#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
13
14namespace device {
15
tommytad8462b2016-08-22 08:09:3916BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic()
17 : weak_ptr_factory_(this) {}
rkc122239752016-04-20 23:59:0818
tommytad8462b2016-08-22 08:09:3919BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() {
20 while (!pending_notify_commands_.empty()) {
21 pending_notify_commands_.front()->Cancel();
22 }
23}
rkc122239752016-04-20 23:59:0824
25std::vector<BluetoothRemoteGattDescriptor*>
26BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID(
tommytad8462b2016-08-22 08:09:3927 const BluetoothUUID& uuid) const {
rkc122239752016-04-20 23:59:0828 std::vector<BluetoothRemoteGattDescriptor*> descriptors;
29 for (BluetoothRemoteGattDescriptor* descriptor : GetDescriptors()) {
30 if (descriptor->GetUUID() == uuid) {
31 descriptors.push_back(descriptor);
32 }
33 }
34 return descriptors;
35}
36
tommytad8462b2016-08-22 08:09:3937base::WeakPtr<device::BluetoothRemoteGattCharacteristic>
38BluetoothRemoteGattCharacteristic::GetWeakPtr() {
39 return weak_ptr_factory_.GetWeakPtr();
40}
41
42bool BluetoothRemoteGattCharacteristic::IsNotifying() const {
43 return !notify_sessions_.empty();
44}
45
46BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand(
47 const ExecuteCallback& execute_callback,
48 const base::Closure& cancel_callback)
49 : execute_callback_(execute_callback), cancel_callback_(cancel_callback) {}
50
51BluetoothRemoteGattCharacteristic::NotifySessionCommand::
Chris Watkins52eb86892017-11-30 06:52:2652 ~NotifySessionCommand() = default;
tommytad8462b2016-08-22 08:09:3953
54void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute() {
55 execute_callback_.Run(COMMAND_NONE, RESULT_SUCCESS,
56 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
57}
58
59void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute(
60 Type previous_command_type,
61 Result previous_command_result,
62 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
63 execute_callback_.Run(previous_command_type, previous_command_result,
64 previous_command_error_code);
65}
66
67void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
68 cancel_callback_.Run();
69}
70
71void BluetoothRemoteGattCharacteristic::StartNotifySession(
72 const NotifySessionCallback& callback,
73 const ErrorCallback& error_callback) {
74 NotifySessionCommand* command = new NotifySessionCommand(
75 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
76 GetWeakPtr(), callback, error_callback),
77 base::Bind(&BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
78 GetWeakPtr(),
79 base::Bind(error_callback,
80 BluetoothRemoteGattService::GATT_ERROR_FAILED)));
81
82 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
83 if (pending_notify_commands_.size() == 1) {
84 command->Execute();
85 }
86}
87
Jan Wilken Dörriea7786fe2018-04-12 12:31:0588bool BluetoothRemoteGattCharacteristic::WriteWithoutResponse(
89 base::span<const uint8_t> value) {
90 NOTIMPLEMENTED();
91 return false;
92}
93
tommytad8462b2016-08-22 08:09:3994void BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession(
95 NotifySessionCallback callback,
96 ErrorCallback error_callback,
97 NotifySessionCommand::Type previous_command_type,
98 NotifySessionCommand::Result previous_command_result,
99 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
100 // If the command that was resolved immediately before this command was run,
101 // this command should be resolved with the same result.
102 if (previous_command_type == NotifySessionCommand::COMMAND_START) {
103 if (previous_command_result == NotifySessionCommand::RESULT_SUCCESS) {
104 base::ThreadTaskRunnerHandle::Get()->PostTask(
105 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52106 base::BindOnce(
tommytad8462b2016-08-22 08:09:39107 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
108 GetWeakPtr(), callback));
109 return;
110 } else {
111 base::ThreadTaskRunnerHandle::Get()->PostTask(
112 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52113 base::BindOnce(
tommytad8462b2016-08-22 08:09:39114 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
115 GetWeakPtr(), error_callback, previous_command_error_code));
116 return;
117 }
118 }
119
120 // Check that the characteristic supports either notifications or
121 // indications.
122 Properties properties = GetProperties();
123 bool hasNotify = (properties & PROPERTY_NOTIFY) != 0;
124 bool hasIndicate = (properties & PROPERTY_INDICATE) != 0;
125
126 if (!hasNotify && !hasIndicate) {
127 LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
128 base::ThreadTaskRunnerHandle::Get()->PostTask(
129 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52130 base::BindOnce(
tommytad8462b2016-08-22 08:09:39131 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
132 GetWeakPtr(), error_callback,
133 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
134 return;
135 }
136
137 // If the characteristic is already notifying, then we don't need to
138 // subscribe again. All we need to do is call the success callback, which
139 // will create and return a session object to the caller.
140 if (IsNotifying()) {
141 base::ThreadTaskRunnerHandle::Get()->PostTask(
142 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52143 base::BindOnce(
tommytad8462b2016-08-22 08:09:39144 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
145 GetWeakPtr(), callback));
146 return;
147 }
148
tommytad8462b2016-08-22 08:09:39149 // Find the Client Characteristic Configuration descriptor.
150 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
151 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
152 ClientCharacteristicConfigurationUuid());
153
154 if (ccc_descriptor.size() != 1u) {
155 LOG(ERROR) << "Found " << ccc_descriptor.size()
156 << " client characteristic configuration descriptors.";
157 base::ThreadTaskRunnerHandle::Get()->PostTask(
158 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52159 base::BindOnce(
tommytad8462b2016-08-22 08:09:39160 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
161 GetWeakPtr(), error_callback,
162 (ccc_descriptor.size() == 0)
163 ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED
164 : BluetoothRemoteGattService::GATT_ERROR_FAILED));
165 return;
166 }
167
168 // Pass the Client Characteristic Configuration descriptor to
169 // SubscribetoNotifications, which will write the correct value to it, and
170 // do whatever else is needed to get the notifications flowing.
171 SubscribeToNotifications(
172 ccc_descriptor[0],
173 base::Bind(
174 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
175 GetWeakPtr(), callback),
176 base::Bind(&BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
177 GetWeakPtr(), error_callback));
tommytad8462b2016-08-22 08:09:39178}
179
180void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
181 base::Closure callback) {
182 std::unique_ptr<NotifySessionCommand> command =
183 std::move(pending_notify_commands_.front());
184 pending_notify_commands_.pop();
185 callback.Run();
186}
187
188void BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess(
189 NotifySessionCallback callback) {
190 std::unique_ptr<NotifySessionCommand> command =
191 std::move(pending_notify_commands_.front());
192
193 std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
194 new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
195 notify_sessions_.insert(notify_session.get());
196 callback.Run(std::move(notify_session));
197
198 pending_notify_commands_.pop();
199 if (!pending_notify_commands_.empty()) {
200 pending_notify_commands_.front()->Execute(
201 NotifySessionCommand::COMMAND_START,
202 NotifySessionCommand::RESULT_SUCCESS,
203 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
204 }
205}
206
207void BluetoothRemoteGattCharacteristic::OnStartNotifySessionError(
208 ErrorCallback error_callback,
209 BluetoothRemoteGattService::GattErrorCode error) {
210 std::unique_ptr<NotifySessionCommand> command =
211 std::move(pending_notify_commands_.front());
212
213 error_callback.Run(error);
214
215 pending_notify_commands_.pop();
216 if (!pending_notify_commands_.empty()) {
217 pending_notify_commands_.front()->Execute(
218 NotifySessionCommand::COMMAND_START, NotifySessionCommand::RESULT_ERROR,
219 error);
220 }
221}
222
223void BluetoothRemoteGattCharacteristic::StopNotifySession(
224 BluetoothGattNotifySession* session,
225 const base::Closure& callback) {
226 NotifySessionCommand* command = new NotifySessionCommand(
227 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
228 GetWeakPtr(), session, callback),
jlebel0b6e2662017-01-19 18:20:47229 base::Bind(&BluetoothRemoteGattCharacteristic::CancelStopNotifySession,
230 GetWeakPtr(), callback));
tommytad8462b2016-08-22 08:09:39231
232 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
233 if (pending_notify_commands_.size() == 1) {
234 command->Execute();
235 }
236}
237
238void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
239 BluetoothGattNotifySession* session,
240 base::Closure callback,
241 NotifySessionCommand::Type previous_command_type,
242 NotifySessionCommand::Result previous_command_result,
243 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
244 std::set<BluetoothGattNotifySession*>::iterator session_iterator =
245 notify_sessions_.find(session);
246
247 // If the session does not even belong to this characteristic, we return an
248 // error right away.
249 if (session_iterator == notify_sessions_.end()) {
250 base::ThreadTaskRunnerHandle::Get()->PostTask(
251 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52252 base::BindOnce(
253 &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
254 GetWeakPtr(), session, callback,
255 BluetoothRemoteGattService::GATT_ERROR_FAILED));
tommytad8462b2016-08-22 08:09:39256 return;
257 }
258
259 // If there are more active sessions, then we return right away.
260 if (notify_sessions_.size() > 1) {
261 base::ThreadTaskRunnerHandle::Get()->PostTask(
262 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52263 base::BindOnce(
tommytad8462b2016-08-22 08:09:39264 &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
265 GetWeakPtr(), session, callback));
266 return;
267 }
268
tommytad8462b2016-08-22 08:09:39269 // Find the Client Characteristic Configuration descriptor.
270 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
271 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
272 ClientCharacteristicConfigurationUuid());
273
274 if (ccc_descriptor.size() != 1u) {
275 LOG(ERROR) << "Found " << ccc_descriptor.size()
276 << " client characteristic configuration descriptors.";
277 base::ThreadTaskRunnerHandle::Get()->PostTask(
278 FROM_HERE,
tzikfa0c1312018-03-07 04:44:52279 base::BindOnce(
280 &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
281 GetWeakPtr(), session, callback,
282 BluetoothRemoteGattService::GATT_ERROR_FAILED));
tommytad8462b2016-08-22 08:09:39283 return;
284 }
285
286 UnsubscribeFromNotifications(
287 ccc_descriptor[0],
288 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
289 GetWeakPtr(), session, callback),
290 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
291 GetWeakPtr(), session, callback));
tommytad8462b2016-08-22 08:09:39292}
293
294void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
295 base::Closure callback) {
296 std::unique_ptr<NotifySessionCommand> command =
297 std::move(pending_notify_commands_.front());
298 pending_notify_commands_.pop();
299 callback.Run();
300}
301
302void BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess(
303 BluetoothGattNotifySession* session,
304 base::Closure callback) {
305 std::unique_ptr<NotifySessionCommand> command =
306 std::move(pending_notify_commands_.front());
307
308 notify_sessions_.erase(session);
309
310 callback.Run();
311
312 pending_notify_commands_.pop();
313 if (!pending_notify_commands_.empty()) {
314 pending_notify_commands_.front()->Execute(
315 NotifySessionCommand::COMMAND_STOP,
316 NotifySessionCommand::RESULT_SUCCESS,
317 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
318 }
319}
320
321void BluetoothRemoteGattCharacteristic::OnStopNotifySessionError(
322 BluetoothGattNotifySession* session,
323 base::Closure callback,
324 BluetoothRemoteGattService::GattErrorCode error) {
325 std::unique_ptr<NotifySessionCommand> command =
326 std::move(pending_notify_commands_.front());
327
328 notify_sessions_.erase(session);
329
330 callback.Run();
331
332 pending_notify_commands_.pop();
333 if (!pending_notify_commands_.empty()) {
334 pending_notify_commands_.front()->Execute(
335 NotifySessionCommand::COMMAND_STOP, NotifySessionCommand::RESULT_ERROR,
336 error);
337 }
338}
339
rkc122239752016-04-20 23:59:08340} // namespace device