OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_win.h" | 5 #include "device/bluetooth/bluetooth_low_energy_win.h" |
6 | 6 |
7 #include <cfg.h> | 7 #include "base/files/file.h" |
8 #define INITGUID // For DEVPKEY_Xxxx guid/pid pairs | |
9 #include <devpkey.h> | |
10 | |
11 #include "base/logging.h" | 8 #include "base/logging.h" |
12 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 10 #include "base/win/scoped_handle.h" |
13 #include "base/win/windows_version.h" | 11 #include "base/win/windows_version.h" |
14 | 12 |
15 namespace { | 13 namespace { |
16 | 14 |
17 using device::win::DeviceRegistryPropertyValue; | 15 using device::win::DeviceRegistryPropertyValue; |
18 using device::win::DevicePropertyValue; | 16 using device::win::DevicePropertyValue; |
| 17 using device::win::BluetoothLowEnergyDeviceInfo; |
| 18 using device::win::BluetoothLowEnergyServiceInfo; |
19 | 19 |
20 const char kPlatformNotSupported[] = | 20 const char kPlatformNotSupported[] = |
21 "Bluetooth Low energy is only supported on Windows 8 and later."; | 21 "Bluetooth Low energy is only supported on Windows 8 and later."; |
22 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; | 22 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; |
23 const char kDeviceInfoError[] = | 23 const char kDeviceInfoError[] = |
24 "Error retrieving Bluetooth LE device information."; | 24 "Error retrieving Bluetooth LE device information."; |
25 const char kDeviceAddressError[] = | 25 const char kDeviceAddressError[] = |
26 "Device instance ID value does not seem to contain a Bluetooth Adapter " | 26 "Device instance ID value does not seem to contain a Bluetooth Adapter " |
27 "address."; | 27 "address."; |
28 const char kDeviceFriendlyNameError[] = "Device name is not valid."; | 28 const char kDeviceFriendlyNameError[] = "Device name is not valid."; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 | 102 |
103 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); | 103 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); |
104 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { | 104 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { |
105 *error = FormatBluetoothError(message, hr); | 105 *error = FormatBluetoothError(message, hr); |
106 return false; | 106 return false; |
107 } | 107 } |
108 | 108 |
109 return true; | 109 return true; |
110 } | 110 } |
111 | 111 |
112 bool CheckSuccess(HRESULT hr, const char* message, std::string* error) { | 112 bool CheckHResult(HRESULT hr, const char* message, std::string* error) { |
113 if (FAILED(hr)) { | 113 if (FAILED(hr)) { |
114 *error = FormatBluetoothError(message, hr); | 114 *error = FormatBluetoothError(message, hr); |
115 return false; | 115 return false; |
116 } | 116 } |
117 | 117 |
118 return true; | 118 return true; |
119 } | 119 } |
120 | 120 |
| 121 bool CheckSuccess(bool success, const char* message, std::string* error) { |
| 122 if (!success) { |
| 123 CheckHResult(HRESULT_FROM_WIN32(GetLastError()), message, error); |
| 124 return false; |
| 125 } |
| 126 |
| 127 return true; |
| 128 } |
| 129 |
| 130 bool CheckNoData(HRESULT hr, size_t length) { |
| 131 if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) |
| 132 return true; |
| 133 |
| 134 if (SUCCEEDED(hr) && length == 0) |
| 135 return true; |
| 136 |
| 137 return false; |
| 138 } |
| 139 |
| 140 bool CheckMoreData(HRESULT hr, const char* message, std::string* error) { |
| 141 if (SUCCEEDED(hr)) { |
| 142 *error = FormatBluetoothError(message, hr); |
| 143 return false; |
| 144 } |
| 145 |
| 146 if (hr != HRESULT_FROM_WIN32(ERROR_MORE_DATA)) { |
| 147 *error = FormatBluetoothError(message, hr); |
| 148 return false; |
| 149 } |
| 150 |
| 151 return true; |
| 152 } |
| 153 |
121 bool CheckExpectedLength(size_t actual_length, | 154 bool CheckExpectedLength(size_t actual_length, |
122 size_t expected_length, | 155 size_t expected_length, |
123 const char* message, | 156 const char* message, |
124 std::string* error) { | 157 std::string* error) { |
125 if (actual_length != expected_length) { | 158 if (actual_length != expected_length) { |
126 *error = FormatBluetoothError(message, E_FAIL); | 159 *error = FormatBluetoothError(message, E_FAIL); |
127 return false; | 160 return false; |
128 } | 161 } |
129 | 162 |
130 return true; | 163 return true; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 } | 269 } |
237 | 270 |
238 if (actual_length >= 1) { | 271 if (actual_length >= 1) { |
239 // Ensure string is zero terminated. | 272 // Ensure string is zero terminated. |
240 instance_id.get()[actual_length - 1] = 0; | 273 instance_id.get()[actual_length - 1] = 0; |
241 device_info->id = base::SysWideToUTF8(instance_id.get()); | 274 device_info->id = base::SysWideToUTF8(instance_id.get()); |
242 } | 275 } |
243 return true; | 276 return true; |
244 } | 277 } |
245 | 278 |
246 bool CollectDeviceFriendlyName( | 279 bool CollectBluetoothLowEnergyDeviceFriendlyName( |
247 const ScopedDeviceInfoSetHandle& device_info_handle, | 280 const ScopedDeviceInfoSetHandle& device_info_handle, |
248 PSP_DEVINFO_DATA device_info_data, | 281 PSP_DEVINFO_DATA device_info_data, |
249 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, | 282 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, |
250 std::string* error) { | 283 std::string* error) { |
251 scoped_ptr<DeviceRegistryPropertyValue> property_value; | 284 scoped_ptr<DeviceRegistryPropertyValue> property_value; |
252 if (!CollectBluetoothLowEnergyDeviceRegistryProperty(device_info_handle, | 285 if (!CollectBluetoothLowEnergyDeviceRegistryProperty(device_info_handle, |
253 device_info_data, | 286 device_info_data, |
254 SPDRP_FRIENDLYNAME, | 287 SPDRP_FRIENDLYNAME, |
255 &property_value, | 288 &property_value, |
256 error)) { | 289 error)) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 | 356 |
324 device_info->connected = !(value->AsUint32() & DN_DEVICE_DISCONNECTED); | 357 device_info->connected = !(value->AsUint32() & DN_DEVICE_DISCONNECTED); |
325 // Windows 8 exposes BLE devices only if they are visible and paired. This | 358 // Windows 8 exposes BLE devices only if they are visible and paired. This |
326 // might change in the future if Windows offers a public API for discovering | 359 // might change in the future if Windows offers a public API for discovering |
327 // and pairing BLE devices. | 360 // and pairing BLE devices. |
328 device_info->visible = true; | 361 device_info->visible = true; |
329 device_info->authenticated = true; | 362 device_info->authenticated = true; |
330 return true; | 363 return true; |
331 } | 364 } |
332 | 365 |
| 366 bool CollectBluetoothLowEnergyDeviceServices( |
| 367 const base::FilePath& device_path, |
| 368 ScopedVector<BluetoothLowEnergyServiceInfo>* services, |
| 369 std::string* error) { |
| 370 base::File file(device_path, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 371 if (!file.IsValid()) { |
| 372 *error = file.ErrorToString(file.error_details()); |
| 373 return false; |
| 374 } |
| 375 |
| 376 USHORT required_length; |
| 377 HRESULT hr = BluetoothGATTGetServices(file.GetPlatformFile(), |
| 378 0, |
| 379 NULL, |
| 380 &required_length, |
| 381 BLUETOOTH_GATT_FLAG_NONE); |
| 382 if (CheckNoData(hr, required_length)) |
| 383 return true; |
| 384 if (!CheckMoreData(hr, kDeviceInfoError, error)) |
| 385 return false; |
| 386 |
| 387 scoped_ptr<BTH_LE_GATT_SERVICE[]> gatt_services( |
| 388 new BTH_LE_GATT_SERVICE[required_length]); |
| 389 USHORT actual_length = required_length; |
| 390 hr = BluetoothGATTGetServices(file.GetPlatformFile(), |
| 391 actual_length, |
| 392 gatt_services.get(), |
| 393 &required_length, |
| 394 BLUETOOTH_GATT_FLAG_NONE); |
| 395 if (!CheckHResult(hr, kDeviceInfoError, error)) |
| 396 return false; |
| 397 if (!CheckExpectedLength( |
| 398 actual_length, required_length, kDeviceInfoError, error)) { |
| 399 return false; |
| 400 } |
| 401 |
| 402 for (USHORT i = 0; i < actual_length; ++i) { |
| 403 BTH_LE_GATT_SERVICE& gatt_service(gatt_services.get()[i]); |
| 404 BluetoothLowEnergyServiceInfo* service_info = |
| 405 new BluetoothLowEnergyServiceInfo(); |
| 406 service_info->uuid = gatt_service.ServiceUuid; |
| 407 services->push_back(service_info); |
| 408 } |
| 409 |
| 410 return true; |
| 411 } |
| 412 |
333 bool CollectBluetoothLowEnergyDeviceInfo( | 413 bool CollectBluetoothLowEnergyDeviceInfo( |
334 const ScopedDeviceInfoSetHandle& device_info_handle, | 414 const ScopedDeviceInfoSetHandle& device_info_handle, |
335 PSP_DEVICE_INTERFACE_DATA device_interface_data, | 415 PSP_DEVICE_INTERFACE_DATA device_interface_data, |
336 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, | 416 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, |
337 std::string* error) { | 417 std::string* error) { |
338 // Retrieve required # of bytes for interface details | 418 // Retrieve required # of bytes for interface details |
339 ULONG required_length = 0; | 419 ULONG required_length = 0; |
340 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, | 420 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, |
341 device_interface_data, | 421 device_interface_data, |
342 NULL, | 422 NULL, |
(...skipping 29 matching lines...) Expand all Loading... |
372 } | 452 } |
373 | 453 |
374 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( | 454 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( |
375 new device::win::BluetoothLowEnergyDeviceInfo()); | 455 new device::win::BluetoothLowEnergyDeviceInfo()); |
376 result->path = | 456 result->path = |
377 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); | 457 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); |
378 if (!CollectBluetoothLowEnergyDeviceInstanceId( | 458 if (!CollectBluetoothLowEnergyDeviceInstanceId( |
379 device_info_handle, &device_info_data, result, error)) { | 459 device_info_handle, &device_info_data, result, error)) { |
380 return false; | 460 return false; |
381 } | 461 } |
382 if (!CollectDeviceFriendlyName( | 462 if (!CollectBluetoothLowEnergyDeviceFriendlyName( |
383 device_info_handle, &device_info_data, result, error)) { | 463 device_info_handle, &device_info_data, result, error)) { |
384 return false; | 464 return false; |
385 } | 465 } |
386 if (!CollectBluetoothLowEnergyDeviceAddress( | 466 if (!CollectBluetoothLowEnergyDeviceAddress( |
387 device_info_handle, &device_info_data, result, error)) { | 467 device_info_handle, &device_info_data, result, error)) { |
388 return false; | 468 return false; |
389 } | 469 } |
390 if (!CollectBluetoothLowEnergyDeviceStatus( | 470 if (!CollectBluetoothLowEnergyDeviceStatus( |
391 device_info_handle, &device_info_data, result, error)) { | 471 device_info_handle, &device_info_data, result, error)) { |
392 return false; | 472 return false; |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 value_(value.Pass()), | 596 value_(value.Pass()), |
517 value_size_(value_size) { | 597 value_size_(value_size) { |
518 } | 598 } |
519 | 599 |
520 uint32_t DevicePropertyValue::AsUint32() const { | 600 uint32_t DevicePropertyValue::AsUint32() const { |
521 CHECK_EQ(property_type_, static_cast<DEVPROPTYPE>(DEVPROP_TYPE_UINT32)); | 601 CHECK_EQ(property_type_, static_cast<DEVPROPTYPE>(DEVPROP_TYPE_UINT32)); |
522 CHECK_EQ(value_size_, sizeof(uint32_t)); | 602 CHECK_EQ(value_size_, sizeof(uint32_t)); |
523 return *reinterpret_cast<uint32_t*>(value_.get()); | 603 return *reinterpret_cast<uint32_t*>(value_.get()); |
524 } | 604 } |
525 | 605 |
| 606 BluetoothLowEnergyServiceInfo::BluetoothLowEnergyServiceInfo() { |
| 607 } |
| 608 |
| 609 BluetoothLowEnergyServiceInfo::~BluetoothLowEnergyServiceInfo() { |
| 610 } |
| 611 |
526 BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() | 612 BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() |
527 : visible(false), authenticated(false), connected(false) { | 613 : visible(false), authenticated(false), connected(false) { |
528 address.ullLong = BLUETOOTH_NULL_ADDRESS; | 614 address.ullLong = BLUETOOTH_NULL_ADDRESS; |
529 } | 615 } |
530 | 616 |
531 BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { | 617 BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { |
532 } | 618 } |
533 | 619 |
534 bool IsBluetoothLowEnergySupported() { | 620 bool IsBluetoothLowEnergySupported() { |
535 return base::win::GetVersion() >= base::win::VERSION_WIN8; | 621 return base::win::GetVersion() >= base::win::VERSION_WIN8; |
(...skipping 22 matching lines...) Expand all Loading... |
558 case kNoMoreDevices: | 644 case kNoMoreDevices: |
559 return true; | 645 return true; |
560 case kError: | 646 case kError: |
561 return false; | 647 return false; |
562 case kOk: | 648 case kOk: |
563 devices->push_back(device_info.release()); | 649 devices->push_back(device_info.release()); |
564 } | 650 } |
565 } | 651 } |
566 } | 652 } |
567 | 653 |
| 654 bool EnumerateKnownBluetoothLowEnergyServices( |
| 655 BluetoothLowEnergyDeviceInfo* device_info, |
| 656 ScopedVector<BluetoothLowEnergyServiceInfo>* services, |
| 657 std::string* error) { |
| 658 return CollectBluetoothLowEnergyDeviceServices( |
| 659 device_info->path, services, error); |
| 660 } |
| 661 |
568 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( | 662 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( |
569 const std::string& instance_id, | 663 const std::string& instance_id, |
570 BLUETOOTH_ADDRESS* btha, | 664 BLUETOOTH_ADDRESS* btha, |
571 std::string* error) { | 665 std::string* error) { |
572 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); | 666 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); |
573 } | 667 } |
574 | 668 |
575 } // namespace win | 669 } // namespace win |
576 } // namespace device | 670 } // namespace device |
OLD | NEW |