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

Unified Diff: device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm

Issue 2767813002: Bluetooth: macOS: Implementing read/write for descriptors (Closed)
Patch Set: NSString/NSNumber type for descriptor value Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
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..9983ade03b54c960e8b152bb18602cc179a6db38 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
@@ -4,17 +4,52 @@
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h"
+#include "base/bind.h"
+#include "base/mac/foundation_util.h"
tapted 2017/04/05 00:38:37 nit: #import
jlebel 2017/04/06 17:48:49 Done.
#include "base/strings/sys_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "device/bluetooth/bluetooth_adapter_mac.h"
tapted 2017/04/05 00:38:37 #import
jlebel 2017/04/06 17:48:49 Done.
#include "device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h"
tapted 2017/04/05 00:38:37 #import as well
jlebel 2017/04/06 17:48:49 Done.
+using base::mac::ObjCCast;
+
namespace device {
+std::vector<uint8_t> VectorValueFromObjC(id objcValue) {
tapted 2017/04/05 00:38:37 objcValue -> objc_value (or just value) - we only
jlebel 2017/04/06 17:48:49 Done.
+ // According to
+ // https://developer.apple.com/reference/corebluetooth/cbdescriptor some
+ // descriptor values can be NSData, NSString or NSNumber.
+ std::vector<uint8_t> value;
+ if ([objcValue isKindOfClass:[NSString class]]) {
+ NSString* string = ObjCCast<NSString>(objcValue);
tapted 2017/04/05 00:38:37 ObjCCast also does isKindOfClass, so there's a bit
jlebel 2017/04/06 17:48:49 about the first "if": I don't understand why we ne
tapted 2017/04/07 04:40:43 Yep - it would be an error if more than one is set
+ const uint8_t* buffer = (const uint8_t*)(string.UTF8String);
tapted 2017/04/05 00:38:37 note style guide prohibits C-style casts (use rein
jlebel 2017/04/06 17:48:49 Done.
+ value.assign(buffer, buffer + string.length);
+ } else if ([objcValue isKindOfClass:[NSNumber class]]) {
+ CFNumberRef number = base::mac::CFCast<CFNumberRef>(objcValue);
+ CFIndex byteSize = CFNumberGetByteSize(number);
+ CFNumberType type = CFNumberGetType(number);
+ uint8_t* buffer = (uint8_t*)malloc(byteSize);
tapted 2017/04/05 00:38:37 memory leak? - nothing frees |buffer|
jlebel 2017/04/06 17:48:49 Done.
+ CFNumberGetValue(number, type, buffer);
+ value.assign(buffer, buffer + byteSize);
+ } else if ([objcValue isKindOfClass:[NSData class]]) {
+ DCHECK([objcValue isKindOfClass:[NSData class]]);
+ NSData* data = ObjCCast<NSData>(objcValue);
+ const uint8_t* buffer = (const uint8_t*)(data.bytes);
tapted 2017/04/05 00:38:37 data.bytes may return nil - this is really dangero
jlebel 2017/04/06 17:48:49 According to the documentation, -[NSData bytes] ca
tapted 2017/04/07 04:40:43 Hm - maybe you're safe with C++ vectors. It scares
+ value.assign(buffer, buffer + data.length);
+ } else {
+ VLOG(1) << "Unexpected value: "
+ << base::SysNSStringToUTF8([objcValue description]);
+ NOTREACHED();
+ }
+ return value;
+}
+
BluetoothRemoteGattDescriptorMac::BluetoothRemoteGattDescriptorMac(
BluetoothRemoteGattCharacteristicMac* characteristic,
CBDescriptor* descriptor)
: gatt_characteristic_(characteristic),
- cb_descriptor_(descriptor, base::scoped_policy::RETAIN) {
+ cb_descriptor_(descriptor, base::scoped_policy::RETAIN),
+ value_read_or_write_in_progress_(false) {
uuid_ =
BluetoothAdapterMac::BluetoothUUIDWithCBUUID([cb_descriptor_.get() UUID]);
identifier_ = base::SysNSStringToUTF8(
@@ -40,7 +75,18 @@ const std::vector<uint8_t>& BluetoothRemoteGattDescriptorMac::GetValue() const {
return value_;
}
-BluetoothRemoteGattDescriptorMac::~BluetoothRemoteGattDescriptorMac() {}
+BluetoothRemoteGattDescriptorMac::~BluetoothRemoteGattDescriptorMac() {
+ if (!read_value_callbacks_.first.is_null()) {
ortuno 2017/04/04 23:39:43 We need tests like [1] to test that this is gettin
jlebel 2017/04/06 17:48:49 crbug.com/709066
+ 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.
@@ -55,19 +101,89 @@ 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.
+// Sends a write request to a remote characteristic descriptor. |callback| is
ortuno 2017/04/04 23:39:43 I think its weird to have these comments in the .m
jlebel 2017/04/06 17:48:49 Done.
+// called to signal success or |error_callback| for failures.
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_.get().value);
tapted 2017/04/05 00:38:37 we don't use ObjC dot notation for NSObjects in Ch
jlebel 2017/04/06 17:48:49 Done. For the code I wrote in other files: crbug.
+ 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 {

Powered by Google App Engine
This is Rietveld 408576698