blob: d98c0ea8d2fcb7f5709672d03305dee3076abfe7 [file] [log] [blame]
// Copyright 2016 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 "device/bluetooth/bluetooth_adapter_win.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_win.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
#include "device/bluetooth/bluetooth_task_manager_win.h"
namespace device {
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_added_notified_(false),
characteristic_value_read_or_write_in_progress_(false),
weak_ptr_factory_(this) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
DCHECK(parent_service_);
DCHECK(characteristic_info_);
task_manager_ =
parent_service_->GetWinAdapter()->GetWinBluetoothTaskManager();
DCHECK(task_manager_);
characteristic_uuid_ =
BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
characteristic_info_->CharacteristicUuid);
characteristic_identifier_ =
parent_service_->GetIdentifier() + "_" +
std::to_string(characteristic_info_->AttributeHandle);
Update();
}
BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
parent_service_->GetWinAdapter()->NotifyGattCharacteristicRemoved(this);
}
std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const {
return characteristic_identifier_;
}
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_->IsBroadcastable)
properties = properties | PROPERTY_BROADCAST;
if (characteristic_info_->IsReadable)
properties = properties | PROPERTY_READ;
if (characteristic_info_->IsWritableWithoutResponse)
properties = properties | PROPERTY_WRITE_WITHOUT_RESPONSE;
if (characteristic_info_->IsWritable)
properties = properties | PROPERTY_WRITE;
if (characteristic_info_->IsNotifiable)
properties = properties | PROPERTY_NOTIFY;
if (characteristic_info_->IsIndicatable)
properties = properties | PROPERTY_INDICATE;
if (characteristic_info_->IsSignedWritable)
properties = properties | PROPERTY_AUTHENTICATED_SIGNED_WRITES;
if (characteristic_info_->HasExtendedProperties)
properties = properties | PROPERTY_EXTENDED_PROPERTIES;
// TODO(crbug.com/589304): Information about PROPERTY_RELIABLE_WRITE and
// PROPERTY_WRITABLE_AUXILIARIES is not available in characteristic_info_
// (BTH_LE_GATT_CHARACTERISTIC).
return properties;
}
BluetoothGattCharacteristic::Permissions
BluetoothRemoteGattCharacteristicWin::GetPermissions() const {
BluetoothGattCharacteristic::Permissions permissions = PERMISSION_NONE;
if (characteristic_info_->IsReadable)
permissions = permissions | PERMISSION_READ;
if (characteristic_info_->IsWritable)
permissions = permissions | PERMISSION_WRITE;
return permissions;
}
bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const {
NOTIMPLEMENTED();
return false;
}
std::vector<BluetoothGattDescriptor*>
BluetoothRemoteGattCharacteristicWin::GetDescriptors() const {
std::vector<BluetoothGattDescriptor*> descriptors;
for (const auto& descriptor : included_descriptors_)
descriptors.push_back(descriptor.second.get());
return descriptors;
}
BluetoothGattDescriptor* BluetoothRemoteGattCharacteristicWin::GetDescriptor(
const std::string& identifier) const {
GattDescriptorMap::const_iterator it = included_descriptors_.find(identifier);
if (it != included_descriptors_.end())
return it->second.get();
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) {
NOTIMPLEMENTED();
error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED);
}
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);
return;
}
if (characteristic_value_read_or_write_in_progress_) {
error_callback.Run(BluetoothGattService::GATT_ERROR_IN_PROGRESS);
return;
}
characteristic_value_read_or_write_in_progress_ = true;
read_characteristic_value_callbacks_ =
std::make_pair(callback, error_callback);
task_manager_->PostReadGattCharacteristicValue(
parent_service_->GetServicePath(), characteristic_info_.get(),
base::Bind(&BluetoothRemoteGattCharacteristicWin::
OnReadRemoteCharacteristicValueCallback,
weak_ptr_factory_.GetWeakPtr()));
}
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);
return;
}
if (characteristic_value_read_or_write_in_progress_) {
error_callback.Run(BluetoothGattService::GATT_ERROR_IN_PROGRESS);
return;
}
characteristic_value_read_or_write_in_progress_ = true;
write_characteristic_value_callbacks_ =
std::make_pair(callback, error_callback);
task_manager_->PostWriteGattCharacteristicValue(
parent_service_->GetServicePath(), characteristic_info_.get(), new_value,
base::Bind(&BluetoothRemoteGattCharacteristicWin::
OnWriteRemoteCharacteristicValueCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothRemoteGattCharacteristicWin::Update() {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
task_manager_->PostGetGattIncludedDescriptors(
parent_service_->GetServicePath(), characteristic_info_.get(),
base::Bind(&BluetoothRemoteGattCharacteristicWin::
OnGetIncludedDescriptorsCallback,
weak_ptr_factory_.GetWeakPtr()));
}
uint16_t BluetoothRemoteGattCharacteristicWin::GetAttributeHandle() const {
return characteristic_info_->AttributeHandle;
}
void BluetoothRemoteGattCharacteristicWin::OnGetIncludedDescriptorsCallback(
scoped_ptr<BTH_LE_GATT_DESCRIPTOR> descriptors,
uint16_t num,
HRESULT hr) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
UpdateIncludedDescriptors(descriptors.get(), num);
if (!characteristic_added_notified_) {
characteristic_added_notified_ = true;
parent_service_->GetWinAdapter()->NotifyGattCharacteristicAdded(this);
}
}
void BluetoothRemoteGattCharacteristicWin::UpdateIncludedDescriptors(
PBTH_LE_GATT_DESCRIPTOR descriptors,
uint16_t num) {
if (num == 0) {
included_descriptors_.clear();
return;
}
// First, remove descriptors that no longer exist.
std::vector<std::string> to_be_removed;
for (const auto& d : included_descriptors_) {
if (!DoesDescriptorExist(descriptors, num, d.second.get()))
to_be_removed.push_back(d.second->GetIdentifier());
}
for (auto id : to_be_removed)
included_descriptors_.erase(id);
// Return if no new descriptors have been added.
if (included_descriptors_.size() == num)
return;
// Add new descriptors.
for (uint16_t i = 0; i < num; i++) {
if (!IsDescriptorDiscovered(descriptors[i].DescriptorUuid,
descriptors[i].AttributeHandle)) {
PBTH_LE_GATT_DESCRIPTOR win_descriptor_info =
new BTH_LE_GATT_DESCRIPTOR();
*win_descriptor_info = descriptors[i];
BluetoothRemoteGattDescriptorWin* descriptor =
new BluetoothRemoteGattDescriptorWin(this, win_descriptor_info,
ui_task_runner_);
included_descriptors_[descriptor->GetIdentifier()] =
make_scoped_ptr(descriptor);
}
}
}
bool BluetoothRemoteGattCharacteristicWin::IsDescriptorDiscovered(
BTH_LE_UUID& uuid,
uint16_t attribute_handle) {
BluetoothUUID bt_uuid =
BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(uuid);
for (const auto& d : included_descriptors_) {
if (bt_uuid == d.second->GetUUID() &&
attribute_handle == d.second->GetAttributeHandle()) {
return true;
}
}
return false;
}
bool BluetoothRemoteGattCharacteristicWin::DoesDescriptorExist(
PBTH_LE_GATT_DESCRIPTOR descriptors,
uint16_t num,
BluetoothRemoteGattDescriptorWin* descriptor) {
for (uint16_t i = 0; i < num; i++) {
BluetoothUUID uuid =
BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
descriptors[i].DescriptorUuid);
if (descriptor->GetUUID() == uuid &&
descriptor->GetAttributeHandle() == descriptors[i].AttributeHandle) {
return true;
}
}
return false;
}
void BluetoothRemoteGattCharacteristicWin::
OnReadRemoteCharacteristicValueCallback(
scoped_ptr<BTH_LE_GATT_CHARACTERISTIC_VALUE> value,
HRESULT hr) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
std::pair<ValueCallback, ErrorCallback> callbacks;
callbacks.swap(read_characteristic_value_callbacks_);
if (FAILED(hr)) {
callbacks.second.Run(HRESULTToGattErrorCode(hr));
} else {
characteristic_value_.clear();
for (ULONG i = 0; i < value->DataSize; i++)
characteristic_value_.push_back(value->Data[i]);
callbacks.first.Run(characteristic_value_);
}
characteristic_value_read_or_write_in_progress_ = false;
}
void BluetoothRemoteGattCharacteristicWin::
OnWriteRemoteCharacteristicValueCallback(HRESULT hr) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
std::pair<base::Closure, ErrorCallback> callbacks;
callbacks.swap(write_characteristic_value_callbacks_);
if (FAILED(hr)) {
callbacks.second.Run(HRESULTToGattErrorCode(hr));
} else {
callbacks.first.Run();
}
characteristic_value_read_or_write_in_progress_ = false;
}
BluetoothGattService::GattErrorCode
BluetoothRemoteGattCharacteristicWin::HRESULTToGattErrorCode(HRESULT hr) {
switch (hr) {
case E_BLUETOOTH_ATT_READ_NOT_PERMITTED:
case E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED:
return BluetoothGattService::GATT_ERROR_NOT_PERMITTED;
case E_BLUETOOTH_ATT_UNKNOWN_ERROR:
return BluetoothGattService::GATT_ERROR_UNKNOWN;
case ERROR_INVALID_USER_BUFFER:
case E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH:
return BluetoothGattService::GATT_ERROR_INVALID_LENGTH;
default:
return BluetoothGattService::GATT_ERROR_FAILED;
}
}
} // namespace device.