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; | |
ortuno
2017/02/28 02:06:50
I think just return. I don't think we want to star
jlebel
2017/02/28 23:16:18
ok.
| |
196 } | |
187 if (error) { | 197 if (error) { |
188 // TODO(http://crbug.com/609320): Need to pass the error. | 198 // TODO(http://crbug.com/609320): Need to pass the error. |
189 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 199 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
190 // a device services. | 200 // a device services. |
191 VLOG(1) << "Can't discover primary services: " | 201 VLOG(1) << "Can't discover primary services: " |
192 << error.localizedDescription.UTF8String << " (" << error.domain | 202 << error.localizedDescription.UTF8String << " (" << error.domain |
193 << ": " << error.code << ")"; | 203 << ": " << error.code << ")"; |
194 return; | 204 return; |
195 } | 205 } |
196 VLOG(1) << "DidDiscoverPrimaryServices."; | 206 VLOG(1) << "DidDiscoverPrimaryServices, pending count: " |
207 << discovery_pending_count_; | |
197 | 208 |
198 if (!IsGattConnected()) { | 209 if (!IsGattConnected()) { |
199 // Don't create services if the device disconnected. | 210 // Don't create services if the device disconnected. |
200 return; | 211 return; |
201 } | 212 } |
202 | 213 |
203 for (CBService* cb_service in GetPeripheral().services) { | 214 for (CBService* cb_service in GetPeripheral().services) { |
204 BluetoothRemoteGattServiceMac* gatt_service = | 215 BluetoothRemoteGattServiceMac* gatt_service = |
205 GetBluetoothRemoteGattService(cb_service); | 216 GetBluetoothRemoteGattService(cb_service); |
206 if (!gatt_service) { | 217 if (!gatt_service) { |
207 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, | 218 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, |
208 true /* is_primary */); | 219 true /* is_primary */); |
209 auto result_iter = gatt_services_.insert(std::make_pair( | 220 auto result_iter = gatt_services_.insert(std::make_pair( |
210 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); | 221 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); |
211 DCHECK(result_iter.second); | 222 DCHECK(result_iter.second); |
212 adapter_->NotifyGattServiceAdded(gatt_service); | 223 adapter_->NotifyGattServiceAdded(gatt_service); |
213 } | 224 } |
214 } | 225 } |
215 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { | 226 if (discovery_pending_count_ == 0) { |
216 device::BluetoothRemoteGattService* gatt_service = it->second.get(); | 227 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { |
217 device::BluetoothRemoteGattServiceMac* gatt_service_mac = | 228 device::BluetoothRemoteGattService* gatt_service = it->second.get(); |
218 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); | 229 device::BluetoothRemoteGattServiceMac* gatt_service_mac = |
219 gatt_service_mac->DiscoverCharacteristics(); | 230 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); |
231 gatt_service_mac->DiscoverCharacteristics(); | |
232 } | |
233 SendNotificationIfDiscoveryComplete(); | |
220 } | 234 } |
221 } | 235 } |
222 | 236 |
223 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( | 237 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( |
224 CBService* cb_service, | 238 CBService* cb_service, |
225 NSError* error) { | 239 NSError* error) { |
226 if (error) { | 240 if (error) { |
227 // TODO(http://crbug.com/609320): Need to pass the error. | 241 // TODO(http://crbug.com/609320): Need to pass the error. |
228 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 242 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
229 VLOG(1) << "Can't discover characteristics: " | 243 VLOG(1) << "Can't discover characteristics: " |
(...skipping 24 matching lines...) Expand all Loading... | |
254 DCHECK(gatt_service); | 268 DCHECK(gatt_service); |
255 VLOG(1) << gatt_service->GetUUID().canonical_value(); | 269 VLOG(1) << gatt_service->GetUUID().canonical_value(); |
256 std::unique_ptr<BluetoothRemoteGattService> scoped_service = | 270 std::unique_ptr<BluetoothRemoteGattService> scoped_service = |
257 std::move(gatt_services_[gatt_service->GetIdentifier()]); | 271 std::move(gatt_services_[gatt_service->GetIdentifier()]); |
258 gatt_services_.erase(gatt_service->GetIdentifier()); | 272 gatt_services_.erase(gatt_service->GetIdentifier()); |
259 adapter_->NotifyGattServiceRemoved(scoped_service.get()); | 273 adapter_->NotifyGattServiceRemoved(scoped_service.get()); |
260 } | 274 } |
261 device_uuids_.ClearServiceUUIDs(); | 275 device_uuids_.ClearServiceUUIDs(); |
262 SetGattServicesDiscoveryComplete(false); | 276 SetGattServicesDiscoveryComplete(false); |
263 adapter_->NotifyDeviceChanged(this); | 277 adapter_->NotifyDeviceChanged(this); |
264 [GetPeripheral() discoverServices:nil]; | 278 DiscoverPrimaryServices(); |
265 } | 279 } |
266 | 280 |
267 void BluetoothLowEnergyDeviceMac::DidUpdateValue( | 281 void BluetoothLowEnergyDeviceMac::DidUpdateValue( |
268 CBCharacteristic* characteristic, | 282 CBCharacteristic* characteristic, |
269 NSError* error) { | 283 NSError* error) { |
270 VLOG(1) << "DidUpdateValue."; | 284 VLOG(1) << "DidUpdateValue."; |
271 BluetoothRemoteGattServiceMac* gatt_service = | 285 BluetoothRemoteGattServiceMac* gatt_service = |
272 GetBluetoothRemoteGattService(characteristic.service); | 286 GetBluetoothRemoteGattService(characteristic.service); |
273 DCHECK(gatt_service); | 287 DCHECK(gatt_service); |
274 gatt_service->DidUpdateValue(characteristic, error); | 288 gatt_service->DidUpdateValue(characteristic, error); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
330 std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress( | 344 std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress( |
331 CBPeripheral* peripheral) { | 345 CBPeripheral* peripheral) { |
332 const size_t kCanonicalAddressNumberOfBytes = 6; | 346 const size_t kCanonicalAddressNumberOfBytes = 6; |
333 char raw[kCanonicalAddressNumberOfBytes]; | 347 char raw[kCanonicalAddressNumberOfBytes]; |
334 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, | 348 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, |
335 sizeof(raw)); | 349 sizeof(raw)); |
336 std::string hash = base::HexEncode(raw, sizeof(raw)); | 350 std::string hash = base::HexEncode(raw, sizeof(raw)); |
337 return BluetoothDevice::CanonicalizeAddress(hash); | 351 return BluetoothDevice::CanonicalizeAddress(hash); |
338 } | 352 } |
339 | 353 |
354 void BluetoothLowEnergyDeviceMac::DiscoverPrimaryServices() { | |
355 VLOG(1) << "DidDiscoverDescriptors pending count" << discovery_pending_count_; | |
356 ++discovery_pending_count_; | |
357 [GetPeripheral() discoverServices:nil]; | |
358 } | |
359 | |
340 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { | 360 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { |
341 // Notify when all services have been discovered. | 361 // Notify when all services have been discovered. |
342 bool discovery_complete = | 362 bool discovery_complete = |
363 discovery_pending_count_ == 0 && | |
343 std::find_if_not( | 364 std::find_if_not( |
344 gatt_services_.begin(), gatt_services_.end(), | 365 gatt_services_.begin(), |
345 [](GattServiceMap::value_type& pair) { | 366 gatt_services_.end(), [](GattServiceMap::value_type & pair) { |
346 BluetoothRemoteGattService* gatt_service = pair.second.get(); | 367 BluetoothRemoteGattService* gatt_service = pair.second.get(); |
347 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) | 368 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) |
348 ->IsDiscoveryComplete(); | 369 ->IsDiscoveryComplete(); |
349 }) == gatt_services_.end(); | 370 }) == gatt_services_.end(); |
350 if (discovery_complete) { | 371 if (discovery_complete) { |
351 device_uuids_.ReplaceServiceUUIDs(gatt_services_); | 372 device_uuids_.ReplaceServiceUUIDs(gatt_services_); |
352 SetGattServicesDiscoveryComplete(true); | 373 SetGattServicesDiscoveryComplete(true); |
353 adapter_->NotifyGattServicesDiscovered(this); | 374 adapter_->NotifyGattServicesDiscovered(this); |
354 adapter_->NotifyDeviceChanged(this); | 375 adapter_->NotifyDeviceChanged(this); |
355 } | 376 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
390 // 2. When we cancel a pending connection request. | 411 // 2. When we cancel a pending connection request. |
391 if (create_gatt_connection_error_callbacks_.empty()) { | 412 if (create_gatt_connection_error_callbacks_.empty()) { |
392 // If there are no pending callbacks then the connection broke (#1). | 413 // If there are no pending callbacks then the connection broke (#1). |
393 DidDisconnectGatt(true /* notifyDeviceChanged */); | 414 DidDisconnectGatt(true /* notifyDeviceChanged */); |
394 return; | 415 return; |
395 } | 416 } |
396 // Else we canceled the connection request (#2). | 417 // Else we canceled the connection request (#2). |
397 // TODO(http://crbug.com/585897): Need to pass the error. | 418 // TODO(http://crbug.com/585897): Need to pass the error. |
398 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); | 419 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); |
399 } | 420 } |
OLD | NEW |