OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/bluetooth/bluetooth_low_energy_device_mac.h" | 5 #include "device/bluetooth/bluetooth_low_energy_device_mac.h" |
6 | 6 |
7 #import <CoreFoundation/CoreFoundation.h> | 7 #import <CoreFoundation/CoreFoundation.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
11 #include "base/mac/scoped_cftyperef.h" | 11 #include "base/mac/scoped_cftyperef.h" |
12 #include "base/mac/sdk_forward_declarations.h" | 12 #include "base/mac/sdk_forward_declarations.h" |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/sys_string_conversions.h" | 15 #include "base/strings/sys_string_conversions.h" |
16 #include "device/bluetooth/bluetooth_adapter_mac.h" | 16 #include "device/bluetooth/bluetooth_adapter_mac.h" |
17 #include "device/bluetooth/bluetooth_device.h" | 17 #include "device/bluetooth/bluetooth_device.h" |
18 #include "device/bluetooth/bluetooth_low_energy_peripheral_delegate.h" | 18 #include "device/bluetooth/bluetooth_low_energy_peripheral_delegate.h" |
19 #include "device/bluetooth/bluetooth_remote_gatt_service_mac.h" | 19 #include "device/bluetooth/bluetooth_remote_gatt_service_mac.h" |
20 | 20 |
21 using device::BluetoothDevice; | 21 using device::BluetoothDevice; |
22 using device::BluetoothLowEnergyDeviceMac; | 22 using device::BluetoothLowEnergyDeviceMac; |
23 | 23 |
24 BluetoothLowEnergyDeviceMac::BluetoothLowEnergyDeviceMac( | 24 BluetoothLowEnergyDeviceMac::BluetoothLowEnergyDeviceMac( |
25 BluetoothAdapterMac* adapter, | 25 BluetoothAdapterMac* adapter, |
26 CBPeripheral* peripheral) | 26 CBPeripheral* peripheral) |
27 : BluetoothDeviceMac(adapter), | 27 : BluetoothDeviceMac(adapter), |
28 peripheral_(peripheral, base::scoped_policy::RETAIN) { | 28 peripheral_(peripheral, base::scoped_policy::RETAIN), |
| 29 discovery_pending_count_(0) { |
29 DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable()); | 30 DCHECK(BluetoothAdapterMac::IsLowEnergyAvailable()); |
30 DCHECK(peripheral_.get()); | 31 DCHECK(peripheral_.get()); |
31 peripheral_delegate_.reset([[BluetoothLowEnergyPeripheralDelegate alloc] | 32 peripheral_delegate_.reset([[BluetoothLowEnergyPeripheralDelegate alloc] |
32 initWithBluetoothLowEnergyDeviceMac:this]); | 33 initWithBluetoothLowEnergyDeviceMac:this]); |
33 [peripheral_ setDelegate:peripheral_delegate_]; | 34 [peripheral_ setDelegate:peripheral_delegate_]; |
34 identifier_ = GetPeripheralIdentifier(peripheral); | 35 identifier_ = GetPeripheralIdentifier(peripheral); |
35 hash_address_ = GetPeripheralHashAddress(peripheral); | 36 hash_address_ = GetPeripheralHashAddress(peripheral); |
36 UpdateTimestamp(); | 37 UpdateTimestamp(); |
37 } | 38 } |
38 | 39 |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 if (!IsGattConnected()) { | 178 if (!IsGattConnected()) { |
178 GetMacAdapter()->CreateGattConnection(this); | 179 GetMacAdapter()->CreateGattConnection(this); |
179 } | 180 } |
180 } | 181 } |
181 | 182 |
182 void BluetoothLowEnergyDeviceMac::DisconnectGatt() { | 183 void BluetoothLowEnergyDeviceMac::DisconnectGatt() { |
183 GetMacAdapter()->DisconnectGatt(this); | 184 GetMacAdapter()->DisconnectGatt(this); |
184 } | 185 } |
185 | 186 |
186 void BluetoothLowEnergyDeviceMac::DidDiscoverPrimaryServices(NSError* error) { | 187 void BluetoothLowEnergyDeviceMac::DidDiscoverPrimaryServices(NSError* error) { |
| 188 --discovery_pending_count_; |
| 189 if (discovery_pending_count_ < 0) { |
| 190 // This should never happens, just in case it happens with a device, |
| 191 // discovery_pending_count_ is set back to 0. |
| 192 VLOG(1) << GetName()->c_str() |
| 193 << ": BluetoothLowEnergyDeviceMac::discovery_pending_count_ " |
| 194 << discovery_pending_count_; |
| 195 discovery_pending_count_ = 0; |
| 196 return; |
| 197 } |
187 if (error) { | 198 if (error) { |
188 // TODO(http://crbug.com/609320): Need to pass the error. | 199 // TODO(http://crbug.com/609320): Need to pass the error. |
189 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 200 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
190 // a device services. | 201 // a device services. |
191 VLOG(1) << "Can't discover primary services: " | 202 VLOG(1) << "Can't discover primary services: " |
192 << error.localizedDescription.UTF8String << " (" << error.domain | 203 << error.localizedDescription.UTF8String << " (" << error.domain |
193 << ": " << error.code << ")"; | 204 << ": " << error.code << ")"; |
194 return; | 205 return; |
195 } | 206 } |
196 VLOG(1) << "DidDiscoverPrimaryServices."; | 207 VLOG(1) << "DidDiscoverPrimaryServices, pending count: " |
| 208 << discovery_pending_count_; |
197 | 209 |
198 if (!IsGattConnected()) { | 210 if (!IsGattConnected()) { |
199 // Don't create services if the device disconnected. | 211 // Don't create services if the device disconnected. |
200 return; | 212 return; |
201 } | 213 } |
202 | 214 |
203 for (CBService* cb_service in GetPeripheral().services) { | 215 for (CBService* cb_service in GetPeripheral().services) { |
204 BluetoothRemoteGattServiceMac* gatt_service = | 216 BluetoothRemoteGattServiceMac* gatt_service = |
205 GetBluetoothRemoteGattService(cb_service); | 217 GetBluetoothRemoteGattService(cb_service); |
206 if (!gatt_service) { | 218 if (!gatt_service) { |
207 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, | 219 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, |
208 true /* is_primary */); | 220 true /* is_primary */); |
209 auto result_iter = gatt_services_.insert(std::make_pair( | 221 auto result_iter = gatt_services_.insert(std::make_pair( |
210 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); | 222 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); |
211 DCHECK(result_iter.second); | 223 DCHECK(result_iter.second); |
212 adapter_->NotifyGattServiceAdded(gatt_service); | 224 adapter_->NotifyGattServiceAdded(gatt_service); |
213 } | 225 } |
214 } | 226 } |
215 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { | 227 if (discovery_pending_count_ == 0) { |
216 device::BluetoothRemoteGattService* gatt_service = it->second.get(); | 228 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { |
217 device::BluetoothRemoteGattServiceMac* gatt_service_mac = | 229 device::BluetoothRemoteGattService* gatt_service = it->second.get(); |
218 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); | 230 device::BluetoothRemoteGattServiceMac* gatt_service_mac = |
219 gatt_service_mac->DiscoverCharacteristics(); | 231 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); |
| 232 gatt_service_mac->DiscoverCharacteristics(); |
| 233 } |
| 234 SendNotificationIfDiscoveryComplete(); |
220 } | 235 } |
221 } | 236 } |
222 | 237 |
223 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( | 238 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( |
224 CBService* cb_service, | 239 CBService* cb_service, |
225 NSError* error) { | 240 NSError* error) { |
226 if (error) { | 241 if (error) { |
227 // TODO(http://crbug.com/609320): Need to pass the error. | 242 // TODO(http://crbug.com/609320): Need to pass the error. |
228 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 243 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
229 VLOG(1) << "Can't discover characteristics: " | 244 VLOG(1) << "Can't discover characteristics: " |
(...skipping 24 matching lines...) Expand all Loading... |
254 DCHECK(gatt_service); | 269 DCHECK(gatt_service); |
255 VLOG(1) << gatt_service->GetUUID().canonical_value(); | 270 VLOG(1) << gatt_service->GetUUID().canonical_value(); |
256 std::unique_ptr<BluetoothRemoteGattService> scoped_service = | 271 std::unique_ptr<BluetoothRemoteGattService> scoped_service = |
257 std::move(gatt_services_[gatt_service->GetIdentifier()]); | 272 std::move(gatt_services_[gatt_service->GetIdentifier()]); |
258 gatt_services_.erase(gatt_service->GetIdentifier()); | 273 gatt_services_.erase(gatt_service->GetIdentifier()); |
259 adapter_->NotifyGattServiceRemoved(scoped_service.get()); | 274 adapter_->NotifyGattServiceRemoved(scoped_service.get()); |
260 } | 275 } |
261 device_uuids_.ClearServiceUUIDs(); | 276 device_uuids_.ClearServiceUUIDs(); |
262 SetGattServicesDiscoveryComplete(false); | 277 SetGattServicesDiscoveryComplete(false); |
263 adapter_->NotifyDeviceChanged(this); | 278 adapter_->NotifyDeviceChanged(this); |
264 [GetPeripheral() discoverServices:nil]; | 279 DiscoverPrimaryServices(); |
265 } | 280 } |
266 | 281 |
267 void BluetoothLowEnergyDeviceMac::DidUpdateValue( | 282 void BluetoothLowEnergyDeviceMac::DidUpdateValue( |
268 CBCharacteristic* characteristic, | 283 CBCharacteristic* characteristic, |
269 NSError* error) { | 284 NSError* error) { |
270 VLOG(1) << "DidUpdateValue."; | 285 VLOG(1) << "DidUpdateValue."; |
271 BluetoothRemoteGattServiceMac* gatt_service = | 286 BluetoothRemoteGattServiceMac* gatt_service = |
272 GetBluetoothRemoteGattService(characteristic.service); | 287 GetBluetoothRemoteGattService(characteristic.service); |
273 DCHECK(gatt_service); | 288 DCHECK(gatt_service); |
274 gatt_service->DidUpdateValue(characteristic, error); | 289 gatt_service->DidUpdateValue(characteristic, error); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress( | 345 std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress( |
331 CBPeripheral* peripheral) { | 346 CBPeripheral* peripheral) { |
332 const size_t kCanonicalAddressNumberOfBytes = 6; | 347 const size_t kCanonicalAddressNumberOfBytes = 6; |
333 char raw[kCanonicalAddressNumberOfBytes]; | 348 char raw[kCanonicalAddressNumberOfBytes]; |
334 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, | 349 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, |
335 sizeof(raw)); | 350 sizeof(raw)); |
336 std::string hash = base::HexEncode(raw, sizeof(raw)); | 351 std::string hash = base::HexEncode(raw, sizeof(raw)); |
337 return BluetoothDevice::CanonicalizeAddress(hash); | 352 return BluetoothDevice::CanonicalizeAddress(hash); |
338 } | 353 } |
339 | 354 |
| 355 void BluetoothLowEnergyDeviceMac::DiscoverPrimaryServices() { |
| 356 VLOG(1) << "DidDiscoverDescriptors pending count" << discovery_pending_count_; |
| 357 ++discovery_pending_count_; |
| 358 [GetPeripheral() discoverServices:nil]; |
| 359 } |
| 360 |
340 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { | 361 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { |
341 // Notify when all services have been discovered. | 362 // Notify when all services have been discovered. |
342 bool discovery_complete = | 363 bool discovery_complete = |
| 364 discovery_pending_count_ == 0 && |
343 std::find_if_not( | 365 std::find_if_not( |
344 gatt_services_.begin(), gatt_services_.end(), | 366 gatt_services_.begin(), |
345 [](GattServiceMap::value_type& pair) { | 367 gatt_services_.end(), [](GattServiceMap::value_type & pair) { |
346 BluetoothRemoteGattService* gatt_service = pair.second.get(); | 368 BluetoothRemoteGattService* gatt_service = pair.second.get(); |
347 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) | 369 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) |
348 ->IsDiscoveryComplete(); | 370 ->IsDiscoveryComplete(); |
349 }) == gatt_services_.end(); | 371 }) == gatt_services_.end(); |
350 if (discovery_complete) { | 372 if (discovery_complete) { |
351 device_uuids_.ReplaceServiceUUIDs(gatt_services_); | 373 device_uuids_.ReplaceServiceUUIDs(gatt_services_); |
352 SetGattServicesDiscoveryComplete(true); | 374 SetGattServicesDiscoveryComplete(true); |
353 adapter_->NotifyGattServicesDiscovered(this); | 375 adapter_->NotifyGattServicesDiscovered(this); |
354 adapter_->NotifyDeviceChanged(this); | 376 adapter_->NotifyDeviceChanged(this); |
355 } | 377 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 // 2. When we cancel a pending connection request. | 412 // 2. When we cancel a pending connection request. |
391 if (create_gatt_connection_error_callbacks_.empty()) { | 413 if (create_gatt_connection_error_callbacks_.empty()) { |
392 // If there are no pending callbacks then the connection broke (#1). | 414 // If there are no pending callbacks then the connection broke (#1). |
393 DidDisconnectGatt(true /* notifyDeviceChanged */); | 415 DidDisconnectGatt(true /* notifyDeviceChanged */); |
394 return; | 416 return; |
395 } | 417 } |
396 // Else we canceled the connection request (#2). | 418 // Else we canceled the connection request (#2). |
397 // TODO(http://crbug.com/585897): Need to pass the error. | 419 // TODO(http://crbug.com/585897): Need to pass the error. |
398 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); | 420 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); |
399 } | 421 } |
OLD | NEW |