blob: 74eec537287b5e0c3963941d0d71979b62b20e6b [file] [log] [blame]
Bailey Forrest070f5a1e2018-03-28 18:17:141// Copyright 2018 The Chromium Authors. All rights reserved.
Bailey Forrest12761022018-03-22 18:50:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Bailey Forrest801a41d2018-03-31 01:01:225#include "chromecast/device/bluetooth/le/remote_device_impl.h"
Bailey Forrest12761022018-03-22 18:50:166
7#include "base/bind.h"
Sebastien Marchand17fa2782019-01-25 19:28:108#include "base/bind_helpers.h"
Bailey Forrest12761022018-03-22 18:50:169#include "chromecast/base/bind_to_task_runner.h"
Bailey Forrest9625bbf12018-08-15 01:27:1710#include "chromecast/device/bluetooth/bluetooth_util.h"
Bailey Forrest801a41d2018-03-31 01:01:2211#include "chromecast/device/bluetooth/le/gatt_client_manager_impl.h"
12#include "chromecast/device/bluetooth/le/remote_characteristic_impl.h"
13#include "chromecast/device/bluetooth/le/remote_descriptor_impl.h"
14#include "chromecast/device/bluetooth/le/remote_service_impl.h"
Bailey Forrest12761022018-03-22 18:50:1615
16namespace chromecast {
17namespace bluetooth {
18
19#define RUN_ON_IO_THREAD(method, ...) \
20 io_task_runner_->PostTask( \
Bailey Forrest801a41d2018-03-31 01:01:2221 FROM_HERE, \
22 base::BindOnce(&RemoteDeviceImpl::method, this, ##__VA_ARGS__));
Bailey Forrest12761022018-03-22 18:50:1623
24#define MAKE_SURE_IO_THREAD(method, ...) \
25 DCHECK(io_task_runner_); \
26 if (!io_task_runner_->BelongsToCurrentThread()) { \
27 RUN_ON_IO_THREAD(method, ##__VA_ARGS__) \
28 return; \
29 }
30
31#define EXEC_CB_AND_RET(cb, ret, ...) \
32 do { \
33 if (cb) { \
34 std::move(cb).Run(ret, ##__VA_ARGS__); \
35 } \
36 return; \
37 } while (0)
38
39#define CHECK_CONNECTED(cb) \
40 do { \
41 if (!connected_) { \
42 LOG(ERROR) << __func__ << "failed: Not connected"; \
43 EXEC_CB_AND_RET(cb, false); \
44 } \
45 } while (0)
46
47#define LOG_EXEC_CB_AND_RET(cb, ret) \
48 do { \
49 if (!ret) { \
50 LOG(ERROR) << __func__ << "failed"; \
51 } \
52 EXEC_CB_AND_RET(cb, ret); \
53 } while (0)
54
Bailey Forrest9625bbf12018-08-15 01:27:1755// static
56constexpr base::TimeDelta RemoteDeviceImpl::kCommandTimeout;
57
Bailey Forrest801a41d2018-03-31 01:01:2258RemoteDeviceImpl::RemoteDeviceImpl(
Bailey Forrest12761022018-03-22 18:50:1659 const bluetooth_v2_shlib::Addr& addr,
Bailey Forrest801a41d2018-03-31 01:01:2260 base::WeakPtr<GattClientManagerImpl> gatt_client_manager,
Bailey Forrest12761022018-03-22 18:50:1661 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
62 : gatt_client_manager_(gatt_client_manager),
63 addr_(addr),
64 io_task_runner_(io_task_runner) {
65 DCHECK(gatt_client_manager);
66 DCHECK(io_task_runner_->BelongsToCurrentThread());
67}
68
Bailey Forrest801a41d2018-03-31 01:01:2269RemoteDeviceImpl::~RemoteDeviceImpl() = default;
Bailey Forrest12761022018-03-22 18:50:1670
Bailey Forrest801a41d2018-03-31 01:01:2271void RemoteDeviceImpl::Connect(StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:4472 MAKE_SURE_IO_THREAD(Connect, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:1673 if (!ConnectSync()) {
74 // Error logged.
75 EXEC_CB_AND_RET(cb, false);
76 }
77
78 connect_cb_ = std::move(cb);
79}
80
Bailey Forrest801a41d2018-03-31 01:01:2281bool RemoteDeviceImpl::ConnectSync() {
Bailey Forrest12761022018-03-22 18:50:1682 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest8a2e40fe2018-08-21 23:43:0083 LOG(INFO) << "Connect(" << util::AddrLastByteString(addr_) << ")";
84
Bailey Forrest12761022018-03-22 18:50:1685 if (!gatt_client_manager_) {
86 LOG(ERROR) << __func__ << " failed: Destroyed";
87 return false;
88 }
89 if (connect_pending_) {
90 LOG(ERROR) << __func__ << " failed: Connection pending";
91 return false;
92 }
93
94 gatt_client_manager_->NotifyConnect(addr_);
Tiansong Cui24640342018-07-31 16:57:4695
Bailey Forrest12761022018-03-22 18:50:1696 connect_pending_ = true;
Tiansong Cui24640342018-07-31 16:57:4697 gatt_client_manager_->EnqueueConnectRequest(addr_);
98
Bailey Forrest12761022018-03-22 18:50:1699 return true;
100}
101
Bailey Forrest801a41d2018-03-31 01:01:22102void RemoteDeviceImpl::Disconnect(StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:44103 MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16104 if (!DisconnectSync()) {
105 // Error logged.
106 EXEC_CB_AND_RET(cb, false);
107 }
108
109 disconnect_cb_ = std::move(cb);
110}
111
Bailey Forrest801a41d2018-03-31 01:01:22112bool RemoteDeviceImpl::DisconnectSync() {
Bailey Forrest12761022018-03-22 18:50:16113 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest8a2e40fe2018-08-21 23:43:00114 LOG(INFO) << "Disconnect(" << util::AddrLastByteString(addr_) << ")";
Bailey Forrest12761022018-03-22 18:50:16115 if (!gatt_client_manager_) {
116 LOG(ERROR) << __func__ << " failed: Destroyed";
117 return false;
118 }
119
120 if (!connected_) {
121 LOG(ERROR) << "Not connected";
122 return false;
123 }
124
125 if (!gatt_client_manager_->gatt_client()->Disconnect(addr_)) {
126 LOG(ERROR) << __func__ << " failed";
127 return false;
128 }
129 disconnect_pending_ = true;
130
131 return true;
132}
133
Tiansong Cui27322542019-01-08 00:56:13134void RemoteDeviceImpl::CreateBond(StatusCallback cb) {
135 MAKE_SURE_IO_THREAD(CreateBond, BindToCurrentSequence(std::move(cb)));
136 LOG(INFO) << "CreateBond(" << util::AddrLastByteString(addr_) << ")";
137 if (!gatt_client_manager_) {
138 LOG(ERROR) << __func__ << " failed: Destroyed";
139 EXEC_CB_AND_RET(cb, false);
140 }
141
142 if (!connected_) {
143 LOG(ERROR) << "Not connected";
144 EXEC_CB_AND_RET(cb, false);
145 }
146
147 if (create_bond_pending_ || remove_bond_pending_) {
148 // TODO(tiansong): b/120489954 Implement queuing and timeout logic.
149 LOG(ERROR) << __func__ << " failed: waiting for pending bond command";
150 EXEC_CB_AND_RET(cb, false);
151 }
152
153 if (bonded_) {
154 LOG(ERROR) << "Already bonded";
155 EXEC_CB_AND_RET(cb, false);
156 }
157
158 if (!gatt_client_manager_->gatt_client()->CreateBond(addr_)) {
159 LOG(ERROR) << __func__ << " failed";
160 EXEC_CB_AND_RET(cb, false);
161 }
162
163 create_bond_pending_ = true;
164 create_bond_cb_ = std::move(cb);
165}
166
167void RemoteDeviceImpl::RemoveBond(StatusCallback cb) {
168 MAKE_SURE_IO_THREAD(RemoveBond, BindToCurrentSequence(std::move(cb)));
169 LOG(INFO) << "RemoveBond(" << util::AddrLastByteString(addr_) << ")";
170 if (!gatt_client_manager_) {
171 LOG(ERROR) << __func__ << " failed: Destroyed";
172 EXEC_CB_AND_RET(cb, false);
173 }
174
175 if (create_bond_pending_ || remove_bond_pending_) {
176 // TODO(tiansong): b/120489954 Implement queuing and timeout logic.
177 LOG(ERROR) << __func__ << " failed: waiting for pending bond command";
178 EXEC_CB_AND_RET(cb, false);
179 }
180
181 if (!bonded_) {
182 LOG(WARNING) << "Not bonded";
183 }
184
185 if (!gatt_client_manager_->gatt_client()->RemoveBond(addr_)) {
186 LOG(ERROR) << __func__ << " failed";
187 EXEC_CB_AND_RET(cb, false);
188 }
189
190 remove_bond_pending_ = true;
191 remove_bond_cb_ = std::move(cb);
192}
193
Bailey Forrest801a41d2018-03-31 01:01:22194void RemoteDeviceImpl::ReadRemoteRssi(RssiCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:44195 MAKE_SURE_IO_THREAD(ReadRemoteRssi, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16196 if (!gatt_client_manager_) {
197 LOG(ERROR) << __func__ << " failed: Destroyed";
198 EXEC_CB_AND_RET(cb, false, 0);
199 }
200
201 if (rssi_pending_) {
202 LOG(ERROR) << "Read remote RSSI already pending";
203 EXEC_CB_AND_RET(cb, false, 0);
204 }
Tiansong Cuicbfc37e2018-07-30 20:06:27205
Bailey Forrest12761022018-03-22 18:50:16206 rssi_pending_ = true;
207 rssi_cb_ = std::move(cb);
Tiansong Cuicbfc37e2018-07-30 20:06:27208 gatt_client_manager_->EnqueueReadRemoteRssiRequest(addr_);
Bailey Forrest12761022018-03-22 18:50:16209}
210
Bailey Forrest801a41d2018-03-31 01:01:22211void RemoteDeviceImpl::RequestMtu(int mtu, StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:44212 MAKE_SURE_IO_THREAD(RequestMtu, mtu, BindToCurrentSequence(std::move(cb)));
Bailey Forrest8a2e40fe2018-08-21 23:43:00213 LOG(INFO) << "RequestMtu(" << util::AddrLastByteString(addr_) << ", " << mtu
214 << ")";
Bailey Forrest5ea6fa62018-06-29 00:02:44215 DCHECK(cb);
Bailey Forrest12761022018-03-22 18:50:16216 if (!gatt_client_manager_) {
217 LOG(ERROR) << __func__ << " failed: Destroyed";
218 EXEC_CB_AND_RET(cb, false);
219 }
220 CHECK_CONNECTED(cb);
Bailey Forrest5ea6fa62018-06-29 00:02:44221 mtu_callbacks_.push(std::move(cb));
222 EnqueueOperation(
Bailey Forrest9625bbf12018-08-15 01:27:17223 __func__, base::BindOnce(&RemoteDeviceImpl::RequestMtuImpl, this, mtu));
Bailey Forrest12761022018-03-22 18:50:16224}
225
Bailey Forrest801a41d2018-03-31 01:01:22226void RemoteDeviceImpl::ConnectionParameterUpdate(int min_interval,
227 int max_interval,
228 int latency,
229 int timeout,
230 StatusCallback cb) {
Bailey Forrest12761022018-03-22 18:50:16231 MAKE_SURE_IO_THREAD(ConnectionParameterUpdate, min_interval, max_interval,
Kyle Lund1de248a2018-03-27 17:26:44232 latency, timeout, BindToCurrentSequence(std::move(cb)));
Bailey Forrest8a2e40fe2018-08-21 23:43:00233 LOG(INFO) << "ConnectionParameterUpdate(" << util::AddrLastByteString(addr_)
234 << ", " << min_interval << ", " << max_interval << ", " << latency
235 << ", " << timeout << ")";
Bailey Forrest12761022018-03-22 18:50:16236 if (!gatt_client_manager_) {
237 LOG(ERROR) << __func__ << " failed: Destroyed";
238 EXEC_CB_AND_RET(cb, false);
239 }
240 CHECK_CONNECTED(cb);
241 bool ret = gatt_client_manager_->gatt_client()->ConnectionParameterUpdate(
242 addr_, min_interval, max_interval, latency, timeout);
243 LOG_EXEC_CB_AND_RET(cb, ret);
244}
245
Bailey Forrest801a41d2018-03-31 01:01:22246bool RemoteDeviceImpl::IsConnected() {
Bailey Forrest12761022018-03-22 18:50:16247 return connected_;
248}
249
Tiansong Cui27322542019-01-08 00:56:13250bool RemoteDeviceImpl::IsBonded() {
251 return bonded_;
252}
253
Bailey Forrest801a41d2018-03-31 01:01:22254int RemoteDeviceImpl::GetMtu() {
Bailey Forrest12761022018-03-22 18:50:16255 return mtu_;
256}
257
Bailey Forrest801a41d2018-03-31 01:01:22258void RemoteDeviceImpl::GetServices(
Bailey Forrest12761022018-03-22 18:50:16259 base::OnceCallback<void(std::vector<scoped_refptr<RemoteService>>)> cb) {
Kyle Lund1de248a2018-03-27 17:26:44260 MAKE_SURE_IO_THREAD(GetServices, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16261 auto ret = GetServicesSync();
262 EXEC_CB_AND_RET(cb, std::move(ret));
263}
264
Bailey Forrest801a41d2018-03-31 01:01:22265std::vector<scoped_refptr<RemoteService>> RemoteDeviceImpl::GetServicesSync() {
Bailey Forrest12761022018-03-22 18:50:16266 DCHECK(io_task_runner_->BelongsToCurrentThread());
267 std::vector<scoped_refptr<RemoteService>> services;
268 services.reserve(uuid_to_service_.size());
269 for (const auto& pair : uuid_to_service_)
270 services.push_back(pair.second);
271
272 return services;
273}
274
Bailey Forrest801a41d2018-03-31 01:01:22275void RemoteDeviceImpl::GetServiceByUuid(
Bailey Forrest12761022018-03-22 18:50:16276 const bluetooth_v2_shlib::Uuid& uuid,
277 base::OnceCallback<void(scoped_refptr<RemoteService>)> cb) {
278 MAKE_SURE_IO_THREAD(GetServiceByUuid, uuid,
Kyle Lund1de248a2018-03-27 17:26:44279 BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16280 auto ret = GetServiceByUuidSync(uuid);
281 EXEC_CB_AND_RET(cb, std::move(ret));
282}
283
Bailey Forrest801a41d2018-03-31 01:01:22284const bluetooth_v2_shlib::Addr& RemoteDeviceImpl::addr() const {
285 return addr_;
286}
287
Bailey Forrest5ea6fa62018-06-29 00:02:44288void RemoteDeviceImpl::ReadCharacteristic(
289 scoped_refptr<RemoteCharacteristicImpl> characteristic,
290 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
291 RemoteCharacteristic::ReadCallback cb) {
292 DCHECK(io_task_runner_->BelongsToCurrentThread());
293 handle_to_characteristic_read_cbs_[characteristic->handle()].push(
294 std::move(cb));
295
Bailey Forrest9625bbf12018-08-15 01:27:17296 EnqueueOperation(
297 __func__, base::BindOnce(&RemoteDeviceImpl::ReadCharacteristicImpl, this,
298 std::move(characteristic), auth_req));
Bailey Forrest5ea6fa62018-06-29 00:02:44299}
300
301void RemoteDeviceImpl::WriteCharacteristic(
302 scoped_refptr<RemoteCharacteristicImpl> characteristic,
303 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
304 bluetooth_v2_shlib::Gatt::WriteType write_type,
305 std::vector<uint8_t> value,
306 RemoteCharacteristic::StatusCallback cb) {
307 DCHECK(io_task_runner_->BelongsToCurrentThread());
308 handle_to_characteristic_write_cbs_[characteristic->handle()].push(
309 std::move(cb));
Bailey Forrest9625bbf12018-08-15 01:27:17310 EnqueueOperation(
311 __func__, base::BindOnce(&RemoteDeviceImpl::WriteCharacteristicImpl, this,
312 std::move(characteristic), auth_req, write_type,
313 std::move(value)));
Bailey Forrest5ea6fa62018-06-29 00:02:44314}
315
316void RemoteDeviceImpl::ReadDescriptor(
317 scoped_refptr<RemoteDescriptorImpl> descriptor,
318 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
319 RemoteDescriptor::ReadCallback cb) {
320 DCHECK(io_task_runner_->BelongsToCurrentThread());
321 handle_to_descriptor_read_cbs_[descriptor->handle()].push(std::move(cb));
322
Bailey Forrest9625bbf12018-08-15 01:27:17323 EnqueueOperation(__func__,
324 base::BindOnce(&RemoteDeviceImpl::ReadDescriptorImpl, this,
Bailey Forrest5ea6fa62018-06-29 00:02:44325 std::move(descriptor), auth_req));
326}
327
328void RemoteDeviceImpl::WriteDescriptor(
329 scoped_refptr<RemoteDescriptorImpl> descriptor,
330 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
331 std::vector<uint8_t> value,
332 RemoteDescriptor::StatusCallback cb) {
333 DCHECK(io_task_runner_->BelongsToCurrentThread());
334 handle_to_descriptor_write_cbs_[descriptor->handle()].push(std::move(cb));
Bailey Forrest9625bbf12018-08-15 01:27:17335 EnqueueOperation(
336 __func__,
337 base::BindOnce(&RemoteDeviceImpl::WriteDescriptorImpl, this,
338 std::move(descriptor), auth_req, std::move(value)));
Bailey Forrest5ea6fa62018-06-29 00:02:44339}
340
Bailey Forrest801a41d2018-03-31 01:01:22341scoped_refptr<RemoteService> RemoteDeviceImpl::GetServiceByUuidSync(
Bailey Forrest12761022018-03-22 18:50:16342 const bluetooth_v2_shlib::Uuid& uuid) {
343 DCHECK(io_task_runner_->BelongsToCurrentThread());
344 auto it = uuid_to_service_.find(uuid);
345 if (it == uuid_to_service_.end())
346 return nullptr;
347
348 return it->second;
349}
350
Bailey Forrest801a41d2018-03-31 01:01:22351void RemoteDeviceImpl::SetConnected(bool connected) {
Bailey Forrest12761022018-03-22 18:50:16352 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest78fa9602018-06-12 23:10:57353 // We only set connected = true and call the callback after services are
354 // discovered.
Bailey Forrest3de59242018-04-26 17:45:33355 if (!connected) {
356 connected_ = false;
Bailey Forrest78fa9602018-06-12 23:10:57357 ConnectComplete(false);
Bailey Forrest12761022018-03-22 18:50:16358 }
359
360 if (disconnect_pending_) {
361 disconnect_pending_ = false;
362 if (disconnect_cb_) {
363 std::move(disconnect_cb_).Run(!connected);
364 }
365 }
366
Bailey Forrest12761022018-03-22 18:50:16367 if (!connected && rssi_pending_) {
368 LOG(ERROR) << "Read remote RSSI failed: disconnected";
369 if (rssi_cb_) {
370 std::move(rssi_cb_).Run(false, 0);
371 }
372 rssi_pending_ = false;
373 }
374
Bailey Forrest3de59242018-04-26 17:45:33375 if (connected) {
376 if (!gatt_client_manager_) {
377 LOG(ERROR) << "Couldn't discover services: Destroyed";
378 return;
379 }
380
381 if (!gatt_client_manager_->gatt_client()->GetServices(addr_)) {
382 LOG(ERROR) << "Couldn't discover services, disconnecting";
383 Disconnect({});
Bailey Forrest78fa9602018-06-12 23:10:57384 ConnectComplete(false);
Bailey Forrest3de59242018-04-26 17:45:33385 }
Bailey Forrestfda35092018-05-16 00:30:44386 } else {
Bailey Forrest5ea6fa62018-06-29 00:02:44387 // Reset state after disconnection
388 mtu_ = kDefaultMtu;
389 ClearServices();
Bailey Forrest3de59242018-04-26 17:45:33390 }
391}
392
Tiansong Cui27322542019-01-08 00:56:13393void RemoteDeviceImpl::SetBonded(bool bonded) {
394 DCHECK(io_task_runner_->BelongsToCurrentThread());
395
396 bonded_ = bonded;
397
398 if (create_bond_pending_) {
399 create_bond_pending_ = false;
400 if (create_bond_cb_) {
401 std::move(create_bond_cb_).Run(bonded);
402 }
403 }
404
405 if (remove_bond_pending_) {
406 remove_bond_pending_ = false;
407 if (remove_bond_cb_) {
408 std::move(remove_bond_cb_).Run(!bonded);
409 }
410 }
411}
412
Bailey Forrest56e71abb2018-05-11 18:50:56413void RemoteDeviceImpl::SetServicesDiscovered(bool discovered) {
Bailey Forrest3de59242018-04-26 17:45:33414 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest56e71abb2018-05-11 18:50:56415 services_discovered_ = discovered;
416 if (!discovered) {
417 return;
418 }
Bailey Forrest3de59242018-04-26 17:45:33419 connected_ = true;
Bailey Forrest78fa9602018-06-12 23:10:57420 ConnectComplete(true);
Bailey Forrest3de59242018-04-26 17:45:33421}
422
423bool RemoteDeviceImpl::GetServicesDiscovered() {
424 DCHECK(io_task_runner_->BelongsToCurrentThread());
425 return services_discovered_;
Bailey Forrest12761022018-03-22 18:50:16426}
427
Bailey Forrest801a41d2018-03-31 01:01:22428void RemoteDeviceImpl::SetMtu(int mtu) {
Bailey Forrest12761022018-03-22 18:50:16429 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest12761022018-03-22 18:50:16430 mtu_ = mtu;
Bailey Forrest5ea6fa62018-06-29 00:02:44431 if (!mtu_callbacks_.empty()) {
432 std::move(mtu_callbacks_.front()).Run(true);
433 mtu_callbacks_.pop();
434 NotifyQueueOperationComplete();
Bailey Forrest12761022018-03-22 18:50:16435 }
436}
437
Bailey Forrest801a41d2018-03-31 01:01:22438scoped_refptr<RemoteCharacteristic> RemoteDeviceImpl::CharacteristicFromHandle(
Bailey Forrest12761022018-03-22 18:50:16439 uint16_t handle) {
440 DCHECK(io_task_runner_->BelongsToCurrentThread());
441 auto it = handle_to_characteristic_.find(handle);
442 if (it == handle_to_characteristic_.end())
443 return nullptr;
444
445 return it->second;
446}
447
Bailey Forrest5ea6fa62018-06-29 00:02:44448void RemoteDeviceImpl::OnCharacteristicRead(bool status,
449 uint16_t handle,
450 const std::vector<uint8_t>& value) {
Bailey Forrest12761022018-03-22 18:50:16451 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest5ea6fa62018-06-29 00:02:44452 auto it = handle_to_characteristic_read_cbs_.find(handle);
453 if (it == handle_to_characteristic_read_cbs_.end() || it->second.empty()) {
454 LOG(ERROR) << "No such characteristic read";
455 } else {
456 std::move(it->second.front()).Run(status, value);
457 it->second.pop();
458 }
459 NotifyQueueOperationComplete();
460}
Bailey Forrest12761022018-03-22 18:50:16461
Bailey Forrest5ea6fa62018-06-29 00:02:44462void RemoteDeviceImpl::OnCharacteristicWrite(bool status, uint16_t handle) {
463 DCHECK(io_task_runner_->BelongsToCurrentThread());
464 auto it = handle_to_characteristic_write_cbs_.find(handle);
465 if (it == handle_to_characteristic_write_cbs_.end() || it->second.empty()) {
466 LOG(ERROR) << "No such characteristic write";
467 } else {
468 std::move(it->second.front()).Run(status);
469 it->second.pop();
470 }
471 NotifyQueueOperationComplete();
472}
473
474void RemoteDeviceImpl::OnDescriptorRead(bool status,
475 uint16_t handle,
476 const std::vector<uint8_t>& value) {
477 DCHECK(io_task_runner_->BelongsToCurrentThread());
478 auto it = handle_to_descriptor_read_cbs_.find(handle);
479 if (it == handle_to_descriptor_read_cbs_.end() || it->second.empty()) {
480 LOG(ERROR) << "No such descriptor read";
481 } else {
482 std::move(it->second.front()).Run(status, value);
483 it->second.pop();
484 }
485 NotifyQueueOperationComplete();
486}
487
488void RemoteDeviceImpl::OnDescriptorWrite(bool status, uint16_t handle) {
489 DCHECK(io_task_runner_->BelongsToCurrentThread());
490 auto it = handle_to_descriptor_write_cbs_.find(handle);
491 if (it == handle_to_descriptor_write_cbs_.end() || it->second.empty()) {
492 LOG(ERROR) << "No such descriptor write";
493 } else {
494 std::move(it->second.front()).Run(status);
495 it->second.pop();
496 }
497 NotifyQueueOperationComplete();
Bailey Forrest12761022018-03-22 18:50:16498}
499
Bailey Forrest801a41d2018-03-31 01:01:22500void RemoteDeviceImpl::OnGetServices(
Bailey Forrest12761022018-03-22 18:50:16501 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
502 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest5ea6fa62018-06-29 00:02:44503 ClearServices();
Bailey Forrest12761022018-03-22 18:50:16504 OnServicesAdded(services);
Bailey Forrest12761022018-03-22 18:50:16505}
506
Bailey Forrest801a41d2018-03-31 01:01:22507void RemoteDeviceImpl::OnServicesRemoved(uint16_t start_handle,
508 uint16_t end_handle) {
Bailey Forrest12761022018-03-22 18:50:16509 DCHECK(io_task_runner_->BelongsToCurrentThread());
510 for (auto it = uuid_to_service_.begin(); it != uuid_to_service_.end();) {
511 if (it->second->handle() >= start_handle &&
512 it->second->handle() <= end_handle) {
513 for (auto& characteristic : it->second->GetCharacteristics()) {
Bailey Forrest12761022018-03-22 18:50:16514 handle_to_characteristic_.erase(characteristic->handle());
515 }
516 it = uuid_to_service_.erase(it);
517 } else {
518 ++it;
519 }
520 }
Bailey Forrest12761022018-03-22 18:50:16521}
522
Bailey Forrest801a41d2018-03-31 01:01:22523void RemoteDeviceImpl::OnServicesAdded(
Bailey Forrest12761022018-03-22 18:50:16524 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
525 DCHECK(io_task_runner_->BelongsToCurrentThread());
526 for (const auto& service : services) {
Bailey Forrest801a41d2018-03-31 01:01:22527 uuid_to_service_[service.uuid] = new RemoteServiceImpl(
528 this, gatt_client_manager_, service, io_task_runner_);
Bailey Forrest12761022018-03-22 18:50:16529 }
530
531 for (const auto& pair : uuid_to_service_) {
532 for (auto& characteristic : pair.second->GetCharacteristics()) {
Bailey Forrest5ea6fa62018-06-29 00:02:44533 handle_to_characteristic_.emplace(
534 characteristic->handle(),
535 static_cast<RemoteCharacteristicImpl*>(characteristic.get()));
Bailey Forrest12761022018-03-22 18:50:16536 }
537 }
Bailey Forrest12761022018-03-22 18:50:16538}
539
Bailey Forrest801a41d2018-03-31 01:01:22540void RemoteDeviceImpl::OnReadRemoteRssiComplete(bool status, int rssi) {
Bailey Forrest12761022018-03-22 18:50:16541 DCHECK(io_task_runner_->BelongsToCurrentThread());
542 rssi_pending_ = false;
543 if (rssi_cb_) {
Tiansong Cuicbfc37e2018-07-30 20:06:27544 std::move(rssi_cb_).Run(status, rssi);
Bailey Forrest12761022018-03-22 18:50:16545 }
546}
547
Bailey Forrest78fa9602018-06-12 23:10:57548void RemoteDeviceImpl::ConnectComplete(bool success) {
549 DCHECK(io_task_runner_->BelongsToCurrentThread());
550 if (connect_pending_) {
551 connect_pending_ = false;
552 if (connect_cb_) {
553 std::move(connect_cb_).Run(success);
554 }
555 }
556}
557
Bailey Forrest9625bbf12018-08-15 01:27:17558void RemoteDeviceImpl::EnqueueOperation(const std::string& name,
559 base::OnceClosure op) {
Bailey Forrest5ea6fa62018-06-29 00:02:44560 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest9625bbf12018-08-15 01:27:17561 command_queue_.emplace_back(name, std::move(op));
Bailey Forrest5ea6fa62018-06-29 00:02:44562
563 // Run the operation if this is the only operation in the queue. Otherwise, it
564 // will be executed when the current operation completes.
565 if (command_queue_.size() == 1) {
Bailey Forrest9625bbf12018-08-15 01:27:17566 RunNextOperation();
Bailey Forrest5ea6fa62018-06-29 00:02:44567 }
568}
569
570void RemoteDeviceImpl::NotifyQueueOperationComplete() {
571 DCHECK(io_task_runner_->BelongsToCurrentThread());
572 DCHECK(!command_queue_.empty());
573 command_queue_.pop_front();
Bailey Forrest9625bbf12018-08-15 01:27:17574 command_timeout_timer_.Stop();
Bailey Forrest5ea6fa62018-06-29 00:02:44575
576 // Run the next operation if there is one in the queue.
577 if (!command_queue_.empty()) {
Bailey Forrest9625bbf12018-08-15 01:27:17578 RunNextOperation();
Bailey Forrest5ea6fa62018-06-29 00:02:44579 }
580}
581
Bailey Forrest9625bbf12018-08-15 01:27:17582void RemoteDeviceImpl::RunNextOperation() {
583 DCHECK(io_task_runner_->BelongsToCurrentThread());
584 DCHECK(!command_queue_.empty());
585 auto& front = command_queue_.front();
586 command_timeout_timer_.Start(
587 FROM_HERE, kCommandTimeout,
588 base::BindRepeating(&RemoteDeviceImpl::OnCommandTimeout, this,
589 front.first));
590 std::move(front.second).Run();
591}
592
Bailey Forrest5ea6fa62018-06-29 00:02:44593void RemoteDeviceImpl::RequestMtuImpl(int mtu) {
594 DCHECK(io_task_runner_->BelongsToCurrentThread());
595 if (gatt_client_manager_->gatt_client()->RequestMtu(addr_, mtu)) {
596 return;
597 }
598
599 LOG(ERROR) << __func__ << " failed";
600 DCHECK(!mtu_callbacks_.empty());
601 std::move(mtu_callbacks_.front()).Run(false);
602 mtu_callbacks_.pop();
603 NotifyQueueOperationComplete();
604}
605
606void RemoteDeviceImpl::ReadCharacteristicImpl(
607 scoped_refptr<RemoteCharacteristicImpl> characteristic,
608 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req) {
609 DCHECK(io_task_runner_->BelongsToCurrentThread());
610 if (gatt_client_manager_->gatt_client()->ReadCharacteristic(
611 addr(), characteristic->characteristic(), auth_req)) {
612 return;
613 }
614
615 LOG(ERROR) << __func__ << " failed";
616 auto it = handle_to_characteristic_read_cbs_.find(characteristic->handle());
617 DCHECK(it != handle_to_characteristic_read_cbs_.end());
618 DCHECK(!it->second.empty());
619 std::move(it->second.front()).Run(false, {});
620 it->second.pop();
621 NotifyQueueOperationComplete();
622}
623
624void RemoteDeviceImpl::WriteCharacteristicImpl(
625 scoped_refptr<RemoteCharacteristicImpl> characteristic,
626 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
627 bluetooth_v2_shlib::Gatt::WriteType write_type,
628 std::vector<uint8_t> value) {
629 DCHECK(io_task_runner_->BelongsToCurrentThread());
630 if (gatt_client_manager_->gatt_client()->WriteCharacteristic(
631 addr(), characteristic->characteristic(), auth_req, write_type,
632 value)) {
633 return;
634 }
635
636 LOG(ERROR) << __func__ << " failed";
637 auto it = handle_to_characteristic_write_cbs_.find(characteristic->handle());
638 DCHECK(it != handle_to_characteristic_write_cbs_.end());
639 DCHECK(!it->second.empty());
640 std::move(it->second.front()).Run(false);
641 it->second.pop();
642 NotifyQueueOperationComplete();
643}
644
645void RemoteDeviceImpl::ReadDescriptorImpl(
646 scoped_refptr<RemoteDescriptorImpl> descriptor,
647 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req) {
648 DCHECK(io_task_runner_->BelongsToCurrentThread());
649 if (gatt_client_manager_->gatt_client()->ReadDescriptor(
650 addr(), descriptor->descriptor(), auth_req)) {
651 return;
652 }
653
654 LOG(ERROR) << __func__ << " failed";
655 auto it = handle_to_descriptor_read_cbs_.find(descriptor->handle());
656 DCHECK(it != handle_to_descriptor_read_cbs_.end());
657 DCHECK(!it->second.empty());
658 std::move(it->second.front()).Run(false, {});
659 it->second.pop();
660 NotifyQueueOperationComplete();
661}
662
663void RemoteDeviceImpl::WriteDescriptorImpl(
664 scoped_refptr<RemoteDescriptorImpl> descriptor,
665 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
666 std::vector<uint8_t> value) {
667 DCHECK(io_task_runner_->BelongsToCurrentThread());
668 if (gatt_client_manager_->gatt_client()->WriteDescriptor(
669 addr(), descriptor->descriptor(), auth_req, value)) {
670 return;
671 }
672
673 LOG(ERROR) << __func__ << " failed";
674 auto it = handle_to_descriptor_write_cbs_.find(descriptor->handle());
675 DCHECK(it != handle_to_descriptor_write_cbs_.end());
676 DCHECK(!it->second.empty());
677 std::move(it->second.front()).Run(false);
678 it->second.pop();
679 NotifyQueueOperationComplete();
680}
681
682void RemoteDeviceImpl::ClearServices() {
683 for (auto& item : handle_to_characteristic_) {
684 item.second->Invalidate();
685 }
686
687 uuid_to_service_.clear();
688 handle_to_characteristic_.clear();
689 command_queue_.clear();
Bailey Forrest9625bbf12018-08-15 01:27:17690 command_timeout_timer_.Stop();
Bailey Forrest5ea6fa62018-06-29 00:02:44691
692 while (!mtu_callbacks_.empty()) {
693 LOG(ERROR) << "RequestMtu failed: disconnected";
694 std::move(mtu_callbacks_.front()).Run(false);
695 mtu_callbacks_.pop();
696 }
697
698 for (auto& item : handle_to_characteristic_read_cbs_) {
699 auto& queue = item.second;
700 while (!queue.empty()) {
701 LOG(ERROR) << "Characteristic read failed: disconnected";
702 std::move(queue.front()).Run(false, {});
703 queue.pop();
704 }
705 }
706 handle_to_characteristic_read_cbs_.clear();
707
708 for (auto& item : handle_to_characteristic_write_cbs_) {
709 auto& queue = item.second;
710 while (!queue.empty()) {
711 LOG(ERROR) << "Characteristic write failed: disconnected";
712 std::move(queue.front()).Run(false);
713 queue.pop();
714 }
715 }
716 handle_to_characteristic_write_cbs_.clear();
717
718 for (auto& item : handle_to_descriptor_read_cbs_) {
719 auto& queue = item.second;
720 while (!queue.empty()) {
721 LOG(ERROR) << "Descriptor read failed: disconnected";
722 std::move(queue.front()).Run(false, {});
723 queue.pop();
724 }
725 }
726 handle_to_descriptor_read_cbs_.clear();
727
728 for (auto& item : handle_to_descriptor_write_cbs_) {
729 auto& queue = item.second;
730 while (!queue.empty()) {
731 LOG(ERROR) << "Descriptor write failed: disconnected";
732 std::move(queue.front()).Run(false);
733 queue.pop();
734 }
735 }
736 handle_to_descriptor_write_cbs_.clear();
737}
738
Bailey Forrest9625bbf12018-08-15 01:27:17739void RemoteDeviceImpl::OnCommandTimeout(const std::string& name) {
740 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest8a2e40fe2018-08-21 23:43:00741 LOG(ERROR) << name << "(" << util::AddrLastByteString(addr_) << ")"
Bailey Forrest9625bbf12018-08-15 01:27:17742 << " timed out. Disconnecting";
743 Disconnect(base::DoNothing());
744}
745
Bailey Forrest12761022018-03-22 18:50:16746} // namespace bluetooth
747} // namespace chromecast