| Index: device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
|
| diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
|
| index 76cda0c349c19726f6917e40af48db3fd210a4a2..d7c5d6c79dcb403460c5868a6de1a14279e319de 100644
|
| --- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
|
| +++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
|
| @@ -4,19 +4,51 @@
|
|
|
| #include "device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h"
|
|
|
| +#include "base/bind.h"
|
| +#import "base/mac/foundation_util.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| -#include "device/bluetooth/bluetooth_adapter_mac.h"
|
| -#include "device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#import "device/bluetooth/bluetooth_adapter_mac.h"
|
| +#import "device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h"
|
| +
|
| +using base::mac::ObjCCast;
|
|
|
| namespace device {
|
|
|
| +std::vector<uint8_t> VectorValueFromObjC(id objc_value) {
|
| + // According to
|
| + // https://developer.apple.com/reference/corebluetooth/cbdescriptor some
|
| + // descriptor values can be NSData, NSString or NSNumber.
|
| + std::vector<uint8_t> value;
|
| + NSData* data = ObjCCast<NSData>(objc_value);
|
| + NSString* as_string = ObjCCast<NSString>(objc_value);
|
| + NSNumber* as_number = ObjCCast<NSNumber>(objc_value);
|
| +
|
| + if (!data && !as_string && as_number) {
|
| + unsigned short descriptor = [as_number shortValue];
|
| + data = [NSData dataWithBytes:&descriptor length:sizeof(descriptor)];
|
| + }
|
| +
|
| + if (!data && as_string)
|
| + data = [as_string dataUsingEncoding:NSUTF8StringEncoding];
|
| +
|
| + if (data) {
|
| + value.resize([data length]);
|
| + [data getBytes:value.data() length:value.size()];
|
| + } else {
|
| + LOG(WARNING) << "Unexpected value: "
|
| + << base::SysNSStringToUTF8([objc_value description]);
|
| + }
|
| + return value;
|
| +}
|
| +
|
| BluetoothRemoteGattDescriptorMac::BluetoothRemoteGattDescriptorMac(
|
| BluetoothRemoteGattCharacteristicMac* characteristic,
|
| CBDescriptor* descriptor)
|
| : gatt_characteristic_(characteristic),
|
| - cb_descriptor_(descriptor, base::scoped_policy::RETAIN) {
|
| - uuid_ =
|
| - BluetoothAdapterMac::BluetoothUUIDWithCBUUID([cb_descriptor_.get() UUID]);
|
| + cb_descriptor_(descriptor, base::scoped_policy::RETAIN),
|
| + value_read_or_write_in_progress_(false) {
|
| + uuid_ = BluetoothAdapterMac::BluetoothUUIDWithCBUUID([cb_descriptor_ UUID]);
|
| identifier_ = base::SysNSStringToUTF8(
|
| [NSString stringWithFormat:@"%s-%p", uuid_.canonical_value().c_str(),
|
| (void*)cb_descriptor_]);
|
| @@ -40,10 +72,19 @@ const std::vector<uint8_t>& BluetoothRemoteGattDescriptorMac::GetValue() const {
|
| return value_;
|
| }
|
|
|
| -BluetoothRemoteGattDescriptorMac::~BluetoothRemoteGattDescriptorMac() {}
|
| +BluetoothRemoteGattDescriptorMac::~BluetoothRemoteGattDescriptorMac() {
|
| + if (!read_value_callbacks_.first.is_null()) {
|
| + std::pair<ValueCallback, ErrorCallback> callbacks;
|
| + callbacks.swap(read_value_callbacks_);
|
| + callbacks.second.Run(BluetoothGattService::GATT_ERROR_FAILED);
|
| + }
|
| + if (!write_value_callbacks_.first.is_null()) {
|
| + std::pair<base::Closure, ErrorCallback> callbacks;
|
| + callbacks.swap(write_value_callbacks_);
|
| + callbacks.second.Run(BluetoothGattService::GATT_ERROR_FAILED);
|
| + }
|
| +}
|
|
|
| -// Returns a pointer to the GATT characteristic that this characteristic
|
| -// descriptor belongs to.
|
| BluetoothRemoteGattCharacteristic*
|
| BluetoothRemoteGattDescriptorMac::GetCharacteristic() const {
|
| return static_cast<BluetoothRemoteGattCharacteristic*>(gatt_characteristic_);
|
| @@ -55,23 +96,91 @@ BluetoothRemoteGattDescriptorMac::GetCharacteristic() const {
|
| void BluetoothRemoteGattDescriptorMac::ReadRemoteDescriptor(
|
| const ValueCallback& callback,
|
| const ErrorCallback& error_callback) {
|
| - NOTIMPLEMENTED();
|
| + if (value_read_or_write_in_progress_) {
|
| + VLOG(1) << *this << ": Read failed, already in progress.";
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(error_callback,
|
| + BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
|
| + return;
|
| + }
|
| + VLOG(1) << *this << ": Read value.";
|
| + value_read_or_write_in_progress_ = true;
|
| + read_value_callbacks_ = std::make_pair(callback, error_callback);
|
| + [GetCBPeripheral() readValueForDescriptor:cb_descriptor_];
|
| }
|
|
|
| -// Sends a write request to a remote characteristic descriptor, to modify the
|
| -// value of the descriptor with the new value |new_value|. |callback| is
|
| -// called to signal success and |error_callback| for failures. This method
|
| -// only applies to remote descriptors and will fail for those that are locally
|
| -// hosted.
|
| void BluetoothRemoteGattDescriptorMac::WriteRemoteDescriptor(
|
| - const std::vector<uint8_t>& new_value,
|
| + const std::vector<uint8_t>& value,
|
| const base::Closure& callback,
|
| const ErrorCallback& error_callback) {
|
| - NOTIMPLEMENTED();
|
| + if (value_read_or_write_in_progress_) {
|
| + VLOG(1) << *this << ": Write failed, already in progress.";
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(error_callback,
|
| + BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
|
| + return;
|
| + }
|
| + VLOG(1) << *this << ": Write value.";
|
| + value_read_or_write_in_progress_ = true;
|
| + write_value_callbacks_ = std::make_pair(callback, error_callback);
|
| + base::scoped_nsobject<NSData> nsdata_value(
|
| + [[NSData alloc] initWithBytes:value.data() length:value.size()]);
|
| + [GetCBPeripheral() writeValue:nsdata_value forDescriptor:GetCBDescriptor()];
|
| +}
|
| +
|
| +void BluetoothRemoteGattDescriptorMac::DidUpdateValueForDescriptor(
|
| + NSError* error) {
|
| + if (!value_read_or_write_in_progress_) {
|
| + VLOG(1) << *this << ": Value updated, no read in progress.";
|
| + return;
|
| + }
|
| + std::pair<ValueCallback, ErrorCallback> callbacks;
|
| + callbacks.swap(read_value_callbacks_);
|
| + value_read_or_write_in_progress_ = false;
|
| + if (error) {
|
| + BluetoothGattService::GattErrorCode error_code =
|
| + BluetoothDeviceMac::GetGattErrorCodeFromNSError(error);
|
| + VLOG(1) << *this << ": Read value failed with error: "
|
| + << BluetoothAdapterMac::String(error)
|
| + << ", converted to error code: " << error_code;
|
| + callbacks.second.Run(error_code);
|
| + return;
|
| + }
|
| + VLOG(1) << *this << ": Value read.";
|
| + value_ = VectorValueFromObjC([cb_descriptor_ value]);
|
| + callbacks.first.Run(value_);
|
| +}
|
| +
|
| +void BluetoothRemoteGattDescriptorMac::DidWriteValueForDescriptor(
|
| + NSError* error) {
|
| + if (!value_read_or_write_in_progress_) {
|
| + VLOG(1) << *this << ": Value written, no write in progress.";
|
| + return;
|
| + }
|
| + std::pair<base::Closure, ErrorCallback> callbacks;
|
| + callbacks.swap(write_value_callbacks_);
|
| + value_read_or_write_in_progress_ = false;
|
| + if (error) {
|
| + BluetoothGattService::GattErrorCode error_code =
|
| + BluetoothDeviceMac::GetGattErrorCodeFromNSError(error);
|
| + VLOG(1) << *this << ": Write value failed with error: "
|
| + << BluetoothAdapterMac::String(error)
|
| + << ", converted to error code: " << error_code;
|
| + callbacks.second.Run(error_code);
|
| + return;
|
| + }
|
| + VLOG(1) << *this << ": Value written.";
|
| + callbacks.first.Run();
|
| +}
|
| +
|
| +CBPeripheral* BluetoothRemoteGattDescriptorMac::GetCBPeripheral() const {
|
| + return gatt_characteristic_->GetCBPeripheral();
|
| }
|
|
|
| CBDescriptor* BluetoothRemoteGattDescriptorMac::GetCBDescriptor() const {
|
| - return cb_descriptor_.get();
|
| + return cb_descriptor_;
|
| }
|
|
|
| DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
|
|
|