Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: device/bluetooth/bluetooth_low_energy_win.cc

Issue 395633003: Enumerate Bluetooth LE services and expose them to chrome.bluetooth API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix x64 build. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_low_energy_win.h ('k') | device/bluetooth/bluetooth_service_record_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698