Add Objective-C++ GATT client wrapper

PiperOrigin-RevId: 557925490
This commit is contained in:
Nick Bourdakos
2023-08-17 13:48:48 -07:00
committed by Copybara-Service
parent 4aa52b45f9
commit 07a94a950d
4 changed files with 225 additions and 0 deletions
+1
View File
@@ -573,6 +573,7 @@ let package = Package(
// Temporarily ignore BLEv2 source files.
// TODO(b/293283024): Stop ignoring these files when BLEv2 migration is complete.
"internal/platform/implementation/apple/ble_gatt_server.mm",
"internal/platform/implementation/apple/ble_gatt_client.mm",
"internal/platform/implementation/apple/ble_peripheral.mm",
"internal/platform/implementation/apple/ble_server_socket.mm",
"internal/platform/implementation/apple/ble_socket.mm",
@@ -107,6 +107,7 @@ objc_library(
objc_library(
name = "ble_v2",
srcs = [
"ble_gatt_client.mm",
"ble_gatt_server.mm",
"ble_peripheral.mm",
"ble_server_socket.mm",
@@ -116,6 +117,7 @@ objc_library(
"utils.mm",
],
hdrs = [
"ble_gatt_client.h",
"ble_gatt_server.h",
"ble_peripheral.h",
"ble_server_socket.h",
@@ -0,0 +1,88 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly
// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation
// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and
// Objective-C++ scores. Oddly, "#import <Foundation/Foundation.h>" does not contribute any points.
// This comment alone should be enough to trick the IDE in to believing this is actually some sort
// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data
#import <Foundation/Foundation.h>
#include <string>
#include <vector>
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/uuid.h"
@class GNCBLEGATTClient;
namespace nearby {
namespace apple {
class GattClient : public api::ble_v2::GattClient {
public:
explicit GattClient(GNCBLEGATTClient *gatt_client_);
~GattClient() override = default;
// Discovers the specified characteristics of a service.
//
// This method blocks until discovery has finished.
//
// Returns whether or not discovery finished successfully.
bool DiscoverServiceAndCharacteristics(const Uuid &service_uuid,
const std::vector<Uuid> &characteristic_uuids) override;
// Retrieves a GATT characteristic.
//
// DiscoverServiceAndCharacteristics() must be called before this method to fetch all available
// services and characteristics first.
//
// On success, returns the characteristic. On error, returns nullptr.
std::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
const Uuid &service_uuid, const Uuid &characteristic_uuid) override;
// Reads the requested characteristic from the associated remote device.
//
// On success, returns the characteristic's value. On error, returns nullptr.
std::optional<std::string> ReadCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic) override;
// Writes a given characteristic and its values to the associated remote device.
//
// Returns whether or not the write was successful.
bool WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic,
absl::string_view value,
api::ble_v2::GattClient::WriteType type) override;
// Enable or disable notifications/indications for a given characteristic.
//
// Once notifications are enabled for a characteristic, on_characteristic_changed_cb will be
// triggered if the remote device indicates that the given characteristic has changed.
//
// Returns whether or not the subscription was successful.
bool SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic &characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)> on_characteristic_changed_cb) override;
// Disconnects an established connection, or cancels a connection attempt currently in progress.
void Disconnect() override;
private:
GNCBLEGATTClient *gatt_client_;
};
} // namespace apple
} // namespace nearby
@@ -0,0 +1,134 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "internal/platform/implementation/apple/ble_gatt_client.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#include <string>
#include <utility>
#include <vector>
#include "internal/platform/implementation/ble_v2.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h"
#import "internal/platform/implementation/apple/ble_utils.h"
#import "GoogleToolboxForMac/GTMLogger.h"
namespace nearby {
namespace apple {
GattClient::GattClient(GNCBLEGATTClient *gatt_client) : gatt_client_(gatt_client) {}
bool GattClient::DiscoverServiceAndCharacteristics(const Uuid &service_uuid,
const std::vector<Uuid> &characteristic_uuids) {
CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid);
NSMutableArray<CBUUID *> *characteristics = [[NSMutableArray alloc] init];
for (const auto &uuid : characteristic_uuids) {
[characteristics addObject:CBUUID128FromCPP(uuid)];
}
NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
__block NSError *blockError = nil;
[gatt_client_ discoverCharacteristicsWithUUIDs:characteristics
serviceUUID:serviceUUID
completionHandler:^(NSError *error) {
[condition lock];
if (error != nil) {
GTMLoggerError(@"Error discovering characteristics: %@", error);
}
blockError = error;
[condition signal];
[condition unlock];
}];
[condition wait];
[condition unlock];
return blockError == nil;
}
std::optional<api::ble_v2::GattCharacteristic> GattClient::GetCharacteristic(
const Uuid &service_uuid, const Uuid &characteristic_uuid) {
CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid);
CBUUID *characteristicUUID = CBUUID128FromCPP(characteristic_uuid);
NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
__block GNCBLEGATTCharacteristic *blockCharacteristic = nil;
__block NSError *blockError = nil;
[gatt_client_ characteristicWithUUID:characteristicUUID
serviceUUID:serviceUUID
completionHandler:^(GNCBLEGATTCharacteristic *characteristic, NSError *error) {
[condition lock];
if (error != nil) {
GTMLoggerError(@"Error retrieving characteristic: %@", error);
}
blockCharacteristic = characteristic;
blockError = error;
[condition signal];
[condition unlock];
}];
[condition wait];
[condition unlock];
if (blockCharacteristic == nil) {
return std::nullopt;
}
return CPPGATTCharacteristicFromObjC(blockCharacteristic);
}
std::optional<std::string> GattClient::ReadCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic) {
NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
__block NSData *blockValue = nil;
__block NSError *blockError = nil;
[gatt_client_ readValueForCharacteristic:ObjCGATTCharacteristicFromCPP(characteristic)
completionHandler:^(NSData *value, NSError *error) {
[condition lock];
if (error != nil) {
GTMLoggerError(@"Error reading characteristic: %@", error);
}
blockValue = value;
blockError = error;
[condition signal];
[condition unlock];
}];
[condition wait];
[condition unlock];
if (blockValue == nil) {
return std::nullopt;
}
return std::string((const char *)blockValue.bytes, blockValue.length);
}
// TODO(b/290385712): Implement.
bool GattClient::WriteCharacteristic(const api::ble_v2::GattCharacteristic &characteristic,
absl::string_view value,
api::ble_v2::GattClient::WriteType type) {
return false;
}
// TODO(b/290385712): Implement.
bool GattClient::SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic &characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)> on_characteristic_changed_cb) {
return false;
}
// TODO(b/290385712): Implement.
void GattClient::Disconnect() {}
} // namespace apple
} // namespace nearby