Index: device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc |
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4df856d8cad10507b3ff5d2cd462e7a40198b2b3 |
--- /dev/null |
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc |
@@ -0,0 +1,424 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" |
+ |
+#include "base/bind.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "device/bluetooth/bluetooth_gatt_notify_session_win.h" |
+ |
+namespace device { |
+ |
+void WinOnRemoteCharacteristicValueChanged(BTH_LE_GATT_EVENT_TYPE type, |
+ PVOID event_parameter, |
+ PVOID context) { |
+ BluetoothRemoteGattCharacteristicWin* characteristic = |
+ (BluetoothRemoteGattCharacteristicWin*)context; |
+ characteristic->OnRemoteCharacteristicValueChanged(type, event_parameter); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin:: |
+ NotifyCharacteristicDiscComplIfNecessary() { |
+ if (descriptor_discovered_ && |
+ completed_descriptors_.size() == included_descriptor_objects_.size() && |
+ (characteristic_value_initialized_ || |
+ !characteristic_info_->IsReadable) && |
+ !complete_notified_) { |
+ parent_service_->NotifyGattCharacteristicAdded(this); |
+ complete_notified_ = true; |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::UpdateIncludedDescriptors( |
+ PBTH_LE_GATT_DESCRIPTOR descriptors, |
+ uint16_t num) { |
+ if (num == 0) { |
+ completed_descriptors_.clear(); |
+ included_descriptor_objects_.clear(); |
+ return; |
+ } |
+ // Map of retrieved descriptor uuid value to its index in |descriptors|. |
+ std::map<std::string, uint16_t> current_descriptors; |
+ for (uint16_t i = 0; i < num; i++) { |
+ current_descriptors[task_manager_->BluetoothLowEnergyUuidToBluetoothUuid( |
+ descriptors[i].DescriptorUuid) |
+ .value()] = i; |
+ } |
+ // Map of known descriptor uuid value to its identifier. |
+ std::map<std::string, std::string> known_descriptors; |
+ if (included_descriptor_objects_.size() != 0) { |
+ for (auto e : included_descriptor_objects_) { |
+ known_descriptors[e.second->GetUUID().value()] = e.first; |
+ } |
+ std::vector<std::string> removed_descriptors; |
+ for (auto e : known_descriptors) { |
+ if (current_descriptors.find(e.first) == current_descriptors.end()) { |
+ removed_descriptors.push_back(e.second); |
+ } |
+ } |
+ for (auto e : removed_descriptors) { |
+ completed_descriptors_.erase(e); |
+ included_descriptor_objects_.erase(e); |
+ } |
+ // Update previously known descriptors. |
+ for (auto e : included_descriptor_objects_) |
+ e.second->Update(); |
+ } |
+ |
+ // Return if no new descriptors have been added. |
+ if (included_descriptor_objects_.size() == num) |
+ return; |
+ |
+ // Add new descriptors. |
+ for (auto e : current_descriptors) { |
+ if (known_descriptors.find(e.first) == known_descriptors.end()) { |
+ PBTH_LE_GATT_DESCRIPTOR win_descriptor_info = |
+ new BTH_LE_GATT_DESCRIPTOR(); |
+ *win_descriptor_info = descriptors[e.second]; |
+ BluetoothRemoteGattDescriptorWin* descriptor_object = |
+ new BluetoothRemoteGattDescriptorWin( |
+ adapter_, parent_service_->GetServicePath(), this, |
+ win_descriptor_info, ui_task_runner_); |
+ included_descriptor_objects_.add( |
+ descriptor_object->GetIdentifier(), |
+ scoped_ptr<BluetoothRemoteGattDescriptorWin>(descriptor_object)); |
+ } |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::GetIncludedDescriptorsCallback( |
+ PBTH_LE_GATT_DESCRIPTOR descriptors, |
+ uint16_t num, |
+ HRESULT hr) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) |
+ return; |
+ descriptor_discovered_ = true; |
+ UpdateIncludedDescriptors(descriptors, num); |
+ NotifyCharacteristicDiscComplIfNecessary(); |
+} |
+ |
+// Called by included descriptors. |
+void BluetoothRemoteGattCharacteristicWin::NotifyGattDescriptorAdded( |
+ BluetoothRemoteGattDescriptorWin* descriptor) { |
+ completed_descriptors_.insert(descriptor->GetIdentifier()); |
+ adapter_->NotifyGattDescriptorAdded(descriptor); |
+ NotifyCharacteristicDiscComplIfNecessary(); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::NotifyGattCharacteristicValueChanged( |
+ uint8_t* new_value, |
+ ULONG size) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ characteristic_value_.clear(); |
+ for (ULONG i = 0; i < size; i++) |
+ characteristic_value_.push_back(new_value[i]); |
+ adapter_->NotifyGattCharacteristicValueChanged(this, characteristic_value_); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::OnRemoteCharacteristicValueChanged( |
+ BTH_LE_GATT_EVENT_TYPE type, |
+ PVOID event_parameter) { |
+ if (type == CharacteristicValueChangedEvent) { |
+ BLUETOOTH_GATT_VALUE_CHANGED_EVENT* event = |
+ (BLUETOOTH_GATT_VALUE_CHANGED_EVENT*)event_parameter; |
+ PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value_win = |
+ event->CharacteristicValue; |
+ |
+ uint8_t* new_value = new uint8_t[new_value_win->DataSize]; |
+ memcpy(new_value, &(new_value_win->Data[0]), new_value_win->DataSize); |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
+ NotifyGattCharacteristicValueChanged, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ base::Owned(new_value), new_value_win->DataSize)); |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback( |
+ BLUETOOTH_GATT_EVENT_HANDLE event_handle, |
+ HRESULT hr) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (FAILED(hr)) { |
+ for (auto callback : start_notifying_callback_) |
+ callback.second.Run(BluetoothGattService::GATT_ERROR_FAILED); |
+ start_notifying_callback_.clear(); |
+ return; |
+ } |
+ |
+ for (auto callback : start_notifying_callback_) { |
+ scoped_ptr<BluetoothGattNotifySessionWin> notify_session( |
+ new BluetoothGattNotifySessionWin(weak_ptr_factory_.GetWeakPtr())); |
+ callback.first.Run(std::move(notify_session)); |
+ number_of_active_notify_sessions_++; |
+ } |
+ start_notifying_callback_.clear(); |
+ registered_event_handle_ = event_handle; |
+ is_notifying_ = true; |
+} |
+ |
+BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin( |
+ BluetoothRemoteGattServiceWin* parent_service, |
+ BTH_LE_GATT_CHARACTERISTIC* characteristic_info, |
+ scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) |
+ : parent_service_(parent_service), |
+ characteristic_info_(characteristic_info), |
+ ui_task_runner_(ui_task_runner), |
+ characteristic_value_initialized_(false), |
+ registered_event_handle_(NULL), |
+ weak_ptr_factory_(this), |
+ complete_notified_(false), |
+ is_notifying_(false), |
+ number_of_active_notify_sessions_(0) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ characteristic_value_.clear(); |
+ included_descriptor_objects_.clear(); |
+ completed_descriptors_.clear(); |
+ read_remote_characteristic_value_callbacks_.clear(); |
+ write_remote_characteristic_value_callback_.clear(); |
+ start_notifying_callback_.clear(); |
+ |
+ adapter_ = parent_service_->GetAdapter(); |
+ task_manager_ = adapter_->GetWinBluetoothTaskManager(); |
+ DCHECK(parent_service_); |
+ DCHECK(characteristic_info_); |
+ DCHECK(adapter_); |
+ DCHECK(task_manager_); |
+ |
+ characteristic_uuid_ = task_manager_->BluetoothLowEnergyUuidToBluetoothUuid( |
+ characteristic_info_->CharacteristicUuid); |
+ Update(); |
+} |
+ |
+BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (registered_event_handle_ != NULL) { |
+ task_manager_->UnregisterCharacteristicValueChangedEvent( |
+ registered_event_handle_); |
+ } |
+ |
+ completed_descriptors_.clear(); |
+ included_descriptor_objects_.clear(); |
+ adapter_->NotifyGattCharacteristicRemoved(this); |
+} |
+ |
+std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const { |
+ return parent_service_->GetIdentifier() + "_" + characteristic_uuid_.value(); |
+} |
+ |
+BluetoothUUID BluetoothRemoteGattCharacteristicWin::GetUUID() const { |
+ return characteristic_uuid_; |
+} |
+ |
+bool BluetoothRemoteGattCharacteristicWin::IsLocal() const { |
+ return false; |
+} |
+ |
+std::vector<uint8_t>& BluetoothRemoteGattCharacteristicWin::GetValue() const { |
+ return const_cast<std::vector<uint8_t>&>(characteristic_value_); |
+} |
+ |
+BluetoothGattService* BluetoothRemoteGattCharacteristicWin::GetService() const { |
+ return parent_service_; |
+} |
+ |
+BluetoothGattCharacteristic::Properties |
+BluetoothRemoteGattCharacteristicWin::GetProperties() const { |
+ BluetoothGattCharacteristic::Properties properties = PROPERTY_NONE; |
+ |
+ if (characteristic_info_.get()->IsBroadcastable) |
+ properties = properties | PROPERTY_BROADCAST; |
+ if (characteristic_info_.get()->IsReadable) |
+ properties = properties | PROPERTY_READ; |
+ if (characteristic_info_.get()->IsWritableWithoutResponse) |
+ properties = properties | PROPERTY_WRITE_WITHOUT_RESPONSE; |
+ if (characteristic_info_.get()->IsWritable) |
+ properties = properties | PROPERTY_WRITE; |
+ if (characteristic_info_.get()->IsNotifiable) |
+ properties = properties | PROPERTY_NOTIFY; |
+ if (characteristic_info_.get()->IsIndicatable) |
+ properties = properties | PROPERTY_INDICATE; |
+ if (characteristic_info_.get()->IsSignedWritable) |
+ properties = properties | PROPERTY_AUTHENTICATED_SIGNED_WRITES; |
+ if (characteristic_info_.get()->HasExtendedProperties) |
+ properties = properties | PROPERTY_EXTENDED_PROPERTIES; |
+ |
+ return properties; |
+} |
+ |
+BluetoothGattCharacteristic::Permissions |
+BluetoothRemoteGattCharacteristicWin::GetPermissions() const { |
+ BluetoothGattCharacteristic::Permissions permissions = PERMISSION_NONE; |
+ |
+ if (characteristic_info_.get()->IsReadable) |
+ permissions = permissions | PERMISSION_READ; |
+ if (characteristic_info_.get()->IsWritable) |
+ permissions = permissions | PERMISSION_WRITE; |
+ |
+ return permissions; |
+} |
+ |
+bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const { |
+ return is_notifying_; |
+} |
+ |
+std::vector<BluetoothGattDescriptor*> |
+BluetoothRemoteGattCharacteristicWin::GetDescriptors() const { |
+ std::vector<BluetoothGattDescriptor*> descriptors; |
+ for (auto descriptor : included_descriptor_objects_) |
+ descriptors.push_back(descriptor.second); |
+ return descriptors; |
+} |
+ |
+BluetoothGattDescriptor* BluetoothRemoteGattCharacteristicWin::GetDescriptor( |
+ const std::string& identifier) const { |
+ GattDescriptorMap::const_iterator it = |
+ included_descriptor_objects_.find(identifier); |
+ if (it != included_descriptor_objects_.end()) |
+ return it->second; |
+ return nullptr; |
+} |
+ |
+bool BluetoothRemoteGattCharacteristicWin::AddDescriptor( |
+ BluetoothGattDescriptor* descriptor) { |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+bool BluetoothRemoteGattCharacteristicWin::UpdateValue( |
+ const std::vector<uint8_t>& value) { |
+ NOTIMPLEMENTED(); |
+ return false; |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::StartNotifySession( |
+ const NotifySessionCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (is_notifying_) { |
+ scoped_ptr<BluetoothGattNotifySessionWin> notify_session( |
+ new BluetoothGattNotifySessionWin(weak_ptr_factory_.GetWeakPtr())); |
+ callback.Run(std::move(notify_session)); |
+ number_of_active_notify_sessions_++; |
+ return; |
+ } |
+ |
+ if (characteristic_info_->IsNotifiable || |
+ characteristic_info_->IsIndicatable) { |
+ start_notifying_callback_.push_back( |
+ std::make_pair(callback, error_callback)); |
+ task_manager_->PostRegisterCharacteristicValueChangedEvent( |
+ parent_service_->GetServicePath(), characteristic_info_.get(), |
+ base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
+ GattEventRegistrationCallback, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ &WinOnRemoteCharacteristicValueChanged, (PVOID) this); |
+ } else { |
+ error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::StopNotifySession() { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (!is_notifying_) |
+ return; |
+ |
+ number_of_active_notify_sessions_--; |
+ if (number_of_active_notify_sessions_ > 0) |
+ return; |
+ task_manager_->UnregisterCharacteristicValueChangedEvent( |
+ registered_event_handle_); |
+ registered_event_handle_ = NULL; |
+ is_notifying_ = false; |
+ number_of_active_notify_sessions_ = 0; |
+ start_notifying_callback_.clear(); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::ReadCharacteristicValueCallback( |
+ PBTH_LE_GATT_CHARACTERISTIC_VALUE value, |
+ HRESULT hr) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (FAILED(hr)) { |
+ LOG(ERROR) << "Failed at reading characteristic value with error "; |
+ for (const auto callback : read_remote_characteristic_value_callbacks_) |
+ callback.second.Run(BluetoothGattService::GATT_ERROR_FAILED); |
+ } else { |
+ characteristic_value_.clear(); |
+ for (ULONG i = 0; i < value->DataSize; i++) |
+ characteristic_value_.push_back(value->Data[i]); |
+ for (const auto callback : read_remote_characteristic_value_callbacks_) |
+ callback.first.Run(characteristic_value_); |
+ } |
+ |
+ if (!characteristic_value_initialized_) { |
+ characteristic_value_initialized_ = true; |
+ NotifyCharacteristicDiscComplIfNecessary(); |
+ } |
+ read_remote_characteristic_value_callbacks_.clear(); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( |
+ const ValueCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (!characteristic_info_.get()->IsReadable) |
+ error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); |
+ |
+ read_remote_characteristic_value_callbacks_.push_back( |
+ std::make_pair(callback, error_callback)); |
+ task_manager_->PostReadCharacteristicValue( |
+ parent_service_->GetServicePath(), characteristic_info_.get(), |
+ base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
+ ReadCharacteristicValueCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristicCallback( |
+ HRESULT hr) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (FAILED(hr)) { |
+ for (const auto callback : write_remote_characteristic_value_callback_) |
+ callback.second.Run(BluetoothGattService::GATT_ERROR_FAILED); |
+ } else { |
+ for (const auto callback : write_remote_characteristic_value_callback_) |
+ callback.first.Run(); |
+ } |
+ write_remote_characteristic_value_callback_.clear(); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic( |
+ const std::vector<uint8_t>& new_value, |
+ const base::Closure& callback, |
+ const ErrorCallback& error_callback) { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (!characteristic_info_.get()->IsWritable) |
+ error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); |
+ |
+ write_remote_characteristic_value_callback_.push_back( |
+ std::make_pair(callback, error_callback)); |
+ task_manager_->PostWriteCharacteristicValue( |
+ parent_service_->GetServicePath(), characteristic_info_.get(), new_value, |
+ base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
+ WriteRemoteCharacteristicCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BluetoothRemoteGattCharacteristicWin::Update() { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ task_manager_->PostGetGattIncludedDescriptors( |
+ parent_service_->GetServicePath(), characteristic_info_.get(), |
+ base::Bind( |
+ &BluetoothRemoteGattCharacteristicWin::GetIncludedDescriptorsCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ |
+ if (characteristic_info_->IsReadable) { |
+ task_manager_->PostReadCharacteristicValue( |
+ parent_service_->GetServicePath(), characteristic_info_.get(), |
+ base::Bind(&BluetoothRemoteGattCharacteristicWin:: |
+ ReadCharacteristicValueCallback, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ } |
+} |
+ |
+} // namespace device. |