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
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
13 #include "device/bluetooth/bluetooth_device.h"
14 #include "device/bluetooth/bluetooth_gatt_notify_session_chromeos.h"
15 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
16 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
23 // Stream operator for logging vector<uint8>.
24 std::ostream
& operator<<(std::ostream
& out
, const std::vector
<uint8
> bytes
) {
26 for (std::vector
<uint8
>::const_iterator iter
= bytes
.begin();
27 iter
!= bytes
.end(); ++iter
) {
28 out
<< base::StringPrintf("%02X", *iter
);
35 BluetoothRemoteGattCharacteristicChromeOS::
36 BluetoothRemoteGattCharacteristicChromeOS(
37 BluetoothRemoteGattServiceChromeOS
* service
,
38 const dbus::ObjectPath
& object_path
)
39 : object_path_(object_path
),
41 num_notify_sessions_(0),
42 notify_call_pending_(false),
43 weak_ptr_factory_(this) {
44 VLOG(1) << "Creating remote GATT characteristic with identifier: "
45 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
46 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
48 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
51 // Add all known GATT characteristic descriptors.
52 const std::vector
<dbus::ObjectPath
>& gatt_descs
=
53 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
55 for (std::vector
<dbus::ObjectPath
>::const_iterator iter
= gatt_descs
.begin();
56 iter
!= gatt_descs
.end(); ++iter
)
57 GattDescriptorAdded(*iter
);
60 BluetoothRemoteGattCharacteristicChromeOS::
61 ~BluetoothRemoteGattCharacteristicChromeOS() {
62 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
64 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
67 // Clean up all the descriptors. There isn't much point in notifying service
68 // observers for each descriptor that gets removed, so just delete them.
69 for (DescriptorMap::iterator iter
= descriptors_
.begin();
70 iter
!= descriptors_
.end(); ++iter
)
73 // Report an error for all pending calls to StartNotifySession.
74 while (!pending_start_notify_calls_
.empty()) {
75 PendingStartNotifyCall callbacks
= pending_start_notify_calls_
.front();
76 pending_start_notify_calls_
.pop();
77 callbacks
.second
.Run();
81 std::string
BluetoothRemoteGattCharacteristicChromeOS::GetIdentifier() const {
82 return object_path_
.value();
86 BluetoothRemoteGattCharacteristicChromeOS::GetUUID() const {
87 BluetoothGattCharacteristicClient::Properties
* properties
=
88 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
89 GetProperties(object_path_
);
91 return device::BluetoothUUID(properties
->uuid
.value());
94 bool BluetoothRemoteGattCharacteristicChromeOS::IsLocal() const {
98 const std::vector
<uint8
>&
99 BluetoothRemoteGattCharacteristicChromeOS::GetValue() const {
100 return cached_value_
;
103 device::BluetoothGattService
*
104 BluetoothRemoteGattCharacteristicChromeOS::GetService() const {
108 device::BluetoothGattCharacteristic::Properties
109 BluetoothRemoteGattCharacteristicChromeOS::GetProperties() const {
110 BluetoothGattCharacteristicClient::Properties
* properties
=
111 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
112 GetProperties(object_path_
);
115 Properties props
= kPropertyNone
;
116 const std::vector
<std::string
>& flags
= properties
->flags
.value();
117 for (std::vector
<std::string
>::const_iterator iter
= flags
.begin();
120 if (*iter
== bluetooth_gatt_characteristic::kFlagBroadcast
)
121 props
|= kPropertyBroadcast
;
122 if (*iter
== bluetooth_gatt_characteristic::kFlagRead
)
123 props
|= kPropertyRead
;
124 if (*iter
== bluetooth_gatt_characteristic::kFlagWriteWithoutResponse
)
125 props
|= kPropertyWriteWithoutResponse
;
126 if (*iter
== bluetooth_gatt_characteristic::kFlagWrite
)
127 props
|= kPropertyWrite
;
128 if (*iter
== bluetooth_gatt_characteristic::kFlagNotify
)
129 props
|= kPropertyNotify
;
130 if (*iter
== bluetooth_gatt_characteristic::kFlagIndicate
)
131 props
|= kPropertyIndicate
;
132 if (*iter
== bluetooth_gatt_characteristic::kFlagAuthenticatedSignedWrites
)
133 props
|= kPropertyAuthenticatedSignedWrites
;
134 if (*iter
== bluetooth_gatt_characteristic::kFlagExtendedProperties
)
135 props
|= kPropertyExtendedProperties
;
136 if (*iter
== bluetooth_gatt_characteristic::kFlagReliableWrite
)
137 props
|= kPropertyReliableWrite
;
138 if (*iter
== bluetooth_gatt_characteristic::kFlagWritableAuxiliaries
)
139 props
|= kPropertyWritableAuxiliaries
;
145 device::BluetoothGattCharacteristic::Permissions
146 BluetoothRemoteGattCharacteristicChromeOS::GetPermissions() const {
147 // TODO(armansito): Once BlueZ defines the permissions, return the correct
149 return kPermissionNone
;
152 bool BluetoothRemoteGattCharacteristicChromeOS::IsNotifying() const {
153 BluetoothGattCharacteristicClient::Properties
* properties
=
154 DBusThreadManager::Get()
155 ->GetBluetoothGattCharacteristicClient()
156 ->GetProperties(object_path_
);
159 return properties
->notifying
.value();
162 std::vector
<device::BluetoothGattDescriptor
*>
163 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptors() const {
164 std::vector
<device::BluetoothGattDescriptor
*> descriptors
;
165 for (DescriptorMap::const_iterator iter
= descriptors_
.begin();
166 iter
!= descriptors_
.end(); ++iter
)
167 descriptors
.push_back(iter
->second
);
171 device::BluetoothGattDescriptor
*
172 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptor(
173 const std::string
& identifier
) const {
174 DescriptorMap::const_iterator iter
=
175 descriptors_
.find(dbus::ObjectPath(identifier
));
176 if (iter
== descriptors_
.end())
181 bool BluetoothRemoteGattCharacteristicChromeOS::AddDescriptor(
182 device::BluetoothGattDescriptor
* descriptor
) {
183 VLOG(1) << "Descriptors cannot be added to a remote GATT characteristic.";
187 bool BluetoothRemoteGattCharacteristicChromeOS::UpdateValue(
188 const std::vector
<uint8
>& value
) {
189 VLOG(1) << "Cannot update the value of a remote GATT characteristic.";
193 void BluetoothRemoteGattCharacteristicChromeOS::ReadRemoteCharacteristic(
194 const ValueCallback
& callback
,
195 const ErrorCallback
& error_callback
) {
196 VLOG(1) << "Sending GATT characteristic read request to characteristic: "
197 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
200 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->ReadValue(
202 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnValueSuccess
,
203 weak_ptr_factory_
.GetWeakPtr(),
205 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError
,
206 weak_ptr_factory_
.GetWeakPtr(),
210 void BluetoothRemoteGattCharacteristicChromeOS::WriteRemoteCharacteristic(
211 const std::vector
<uint8
>& new_value
,
212 const base::Closure
& callback
,
213 const ErrorCallback
& error_callback
) {
214 VLOG(1) << "Sending GATT characteristic write request to characteristic: "
215 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
216 << ", with value: " << new_value
<< ".";
218 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->WriteValue(
222 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError
,
223 weak_ptr_factory_
.GetWeakPtr(),
227 void BluetoothRemoteGattCharacteristicChromeOS::StartNotifySession(
228 const NotifySessionCallback
& callback
,
229 const ErrorCallback
& error_callback
) {
232 if (num_notify_sessions_
> 0) {
233 // The characteristic might have stopped notifying even though the session
234 // count is nonzero. This means that notifications stopped outside of our
235 // control and we should reset the count. If the characteristic is still
236 // notifying, then return success. Otherwise, reset the count and treat
237 // this call as if the count were 0.
239 // Check for overflows, though unlikely.
240 if (num_notify_sessions_
== std::numeric_limits
<size_t>::max()) {
241 error_callback
.Run();
245 ++num_notify_sessions_
;
247 DCHECK(service_
->GetAdapter());
248 DCHECK(service_
->GetDevice());
249 scoped_ptr
<device::BluetoothGattNotifySession
> session(
250 new BluetoothGattNotifySessionChromeOS(
251 service_
->GetAdapter(),
252 service_
->GetDevice()->GetAddress(),
253 service_
->GetIdentifier(),
256 callback
.Run(session
.Pass());
260 num_notify_sessions_
= 0;
263 // Queue the callbacks if there is a pending call to bluetoothd.
264 if (notify_call_pending_
) {
265 pending_start_notify_calls_
.push(std::make_pair(callback
, error_callback
));
269 notify_call_pending_
= true;
270 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StartNotify(
273 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess
,
274 weak_ptr_factory_
.GetWeakPtr(),
276 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError
,
277 weak_ptr_factory_
.GetWeakPtr(),
281 void BluetoothRemoteGattCharacteristicChromeOS::RemoveNotifySession(
282 const base::Closure
& callback
) {
285 if (num_notify_sessions_
> 1) {
286 DCHECK(!notify_call_pending_
);
287 --num_notify_sessions_
;
292 // Notifications may have stopped outside our control. If the characteristic
293 // is no longer notifying, return success.
294 if (!IsNotifying()) {
295 num_notify_sessions_
= 0;
300 if (notify_call_pending_
|| num_notify_sessions_
== 0) {
305 DCHECK(num_notify_sessions_
== 1);
306 notify_call_pending_
= true;
307 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StopNotify(
310 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess
,
311 weak_ptr_factory_
.GetWeakPtr(),
313 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError
,
314 weak_ptr_factory_
.GetWeakPtr(),
318 void BluetoothRemoteGattCharacteristicChromeOS::GattCharacteristicValueUpdated(
319 const dbus::ObjectPath
& object_path
,
320 const std::vector
<uint8
>& value
) {
321 if (object_path
!= object_path_
)
324 cached_value_
= value
;
326 VLOG(1) << "GATT characteristic value has changed: " << object_path
.value()
329 service_
->NotifyCharacteristicValueChanged(this, value
);
332 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded(
333 const dbus::ObjectPath
& object_path
) {
334 if (descriptors_
.find(object_path
) != descriptors_
.end()) {
335 VLOG(1) << "Remote GATT characteristic descriptor already exists: "
336 << object_path
.value();
340 BluetoothGattDescriptorClient::Properties
* properties
=
341 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
342 GetProperties(object_path
);
344 if (properties
->characteristic
.value() != object_path_
) {
345 VLOG(3) << "Remote GATT descriptor does not belong to this characteristic.";
349 VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: "
350 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
352 BluetoothRemoteGattDescriptorChromeOS
* descriptor
=
353 new BluetoothRemoteGattDescriptorChromeOS(this, object_path
);
354 descriptors_
[object_path
] = descriptor
;
355 DCHECK(descriptor
->GetIdentifier() == object_path
.value());
356 DCHECK(descriptor
->GetUUID().IsValid());
359 service_
->NotifyDescriptorAddedOrRemoved(this, descriptor
, true /* added */);
362 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorRemoved(
363 const dbus::ObjectPath
& object_path
) {
364 DescriptorMap::iterator iter
= descriptors_
.find(object_path
);
365 if (iter
== descriptors_
.end()) {
366 VLOG(2) << "Unknown descriptor removed: " << object_path
.value();
370 VLOG(1) << "Removing remote GATT descriptor from characteristic: "
371 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
373 BluetoothRemoteGattDescriptorChromeOS
* descriptor
= iter
->second
;
374 DCHECK(descriptor
->object_path() == object_path
);
375 descriptors_
.erase(iter
);
378 service_
->NotifyDescriptorAddedOrRemoved(this, descriptor
, false /* added */);
383 void BluetoothRemoteGattCharacteristicChromeOS::OnValueSuccess(
384 const ValueCallback
& callback
,
385 const std::vector
<uint8
>& value
) {
386 VLOG(1) << "Characteristic value read: " << value
;
387 cached_value_
= value
;
390 service_
->NotifyCharacteristicValueChanged(this, cached_value_
);
395 void BluetoothRemoteGattCharacteristicChromeOS::OnError(
396 const ErrorCallback
& error_callback
,
397 const std::string
& error_name
,
398 const std::string
& error_message
) {
399 VLOG(1) << "Operation failed: " << error_name
<< ", message: "
401 error_callback
.Run();
404 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess(
405 const NotifySessionCallback
& callback
) {
406 VLOG(1) << "Started notifications from characteristic: "
407 << object_path_
.value();
408 DCHECK(num_notify_sessions_
== 0);
409 DCHECK(notify_call_pending_
);
411 ++num_notify_sessions_
;
412 notify_call_pending_
= false;
414 // Invoke the queued callbacks for this operation.
416 DCHECK(service_
->GetDevice());
417 scoped_ptr
<device::BluetoothGattNotifySession
> session(
418 new BluetoothGattNotifySessionChromeOS(
419 service_
->GetAdapter(),
420 service_
->GetDevice()->GetAddress(),
421 service_
->GetIdentifier(),
424 callback
.Run(session
.Pass());
426 ProcessStartNotifyQueue();
429 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError(
430 const ErrorCallback
& error_callback
,
431 const std::string
& error_name
,
432 const std::string
& error_message
) {
433 VLOG(1) << "Failed to start notifications from characteristic: "
434 << object_path_
.value() << ": " << error_name
<< ", "
436 DCHECK(num_notify_sessions_
== 0);
437 DCHECK(notify_call_pending_
);
439 notify_call_pending_
= false;
440 error_callback
.Run();
442 ProcessStartNotifyQueue();
445 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess(
446 const base::Closure
& callback
) {
447 DCHECK(notify_call_pending_
);
448 DCHECK(num_notify_sessions_
== 1);
450 notify_call_pending_
= false;
451 --num_notify_sessions_
;
454 ProcessStartNotifyQueue();
457 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError(
458 const base::Closure
& callback
,
459 const std::string
& error_name
,
460 const std::string
& error_message
) {
461 VLOG(1) << "Call to stop notifications failed for characteristic: "
462 << object_path_
.value() << ": " << error_name
<< ", "
465 // Since this is a best effort operation, treat this as success.
466 OnStopNotifySuccess(callback
);
469 void BluetoothRemoteGattCharacteristicChromeOS::ProcessStartNotifyQueue() {
470 while (!pending_start_notify_calls_
.empty()) {
471 PendingStartNotifyCall callbacks
= pending_start_notify_calls_
.front();
472 pending_start_notify_calls_
.pop();
473 StartNotifySession(callbacks
.first
, callbacks
.second
);
477 } // namespace chromeos