/*
* Copyright (C) 2024-2026 Huawei Device Co., Ltd.
* 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
*
* http://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 "BluetoothCentralManager.h"
#import "BluetoothUntils.h"
#include "bluetooth_def.h"
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) \
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) { \
block(); \
} else { \
dispatch_async(dispatch_get_main_queue(), block); \
}
#endif
@interface BluetoothCentralManager ()
- (void)setCharacteristicBlock:(id)block forKey:(NSString*)strKey;
- (id)characteristicBlockForKey:(NSString*)strKey;
- (void)removeCharacteristicBlockForKey:(NSString*)strKey;
- (void)cacheNotifyBlock:(NotifyCharacterBlock)block enable:(BOOL)enable key:(NSString*)strKey;
- (NotifyCharacterBlock)notifyBlockForKey:(NSString*)strKey;
- (int)requestNotifyStateForPeripheral:(CBPeripheral*)peripheral
characteristic:(CBCharacteristic*)characteristic
enable:(BOOL)enable
key:(NSString*)strKey
block:(NotifyCharacterBlock)block
completion:(NotifyStateCompletionBlock)completion;
@end
@implementation BluetoothCentralManager
static NSString* strYes = @"1";
static NSString* strNo = @"0";
static const int NOTIFY_STATE_TIMEOUT_SECONDS = 5;
static NSString* BuildNotifyCharacteristicKey(NSString* serviceUuid, NSString* characterUuid)
{
return [NSString stringWithFormat:@"%@%@notifyCharacteristic",
[BluetoothUntils NormalizeBluetoothUuid:serviceUuid], [BluetoothUntils NormalizeBluetoothUuid:characterUuid]];
}
static NSString* BuildDescriptorOperationKey(
NSString* serviceUuid, NSString* characterUuid, NSString* descriptorUuid, NSString* operation)
{
return [NSString stringWithFormat:@"%@%@%@%@",
[BluetoothUntils NormalizeBluetoothUuid:serviceUuid], [BluetoothUntils NormalizeBluetoothUuid:characterUuid],
[BluetoothUntils NormalizeBluetoothUuid:descriptorUuid], operation];
}
+ (BluetoothCentralManager*)sharedInstance
{
static BluetoothCentralManager* bluetoothCentralManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bluetoothCentralManager = [[BluetoothCentralManager alloc] init];
});
return bluetoothCentralManager;
}
- (NSMutableArray*)arrAutoConnectDivice
{
if (!_arrAutoConnectDivice) {
_arrAutoConnectDivice = [NSMutableArray array];
}
return _arrAutoConnectDivice;
}
- (NSMutableDictionary*)diviceIdDic
{
if (!_diviceIdDic) {
_diviceIdDic = [NSMutableDictionary dictionary];
}
return _diviceIdDic;
}
- (NSMutableDictionary*)servicesDic
{
if (!_servicesDic) {
_servicesDic = [NSMutableDictionary dictionary];
}
return _servicesDic;
}
- (NSMutableDictionary*)characteristicBlockDic
{
if (!_characteristicBlockDic) {
_characteristicBlockDic = [NSMutableDictionary dictionary];
}
return _characteristicBlockDic;
}
- (NSMutableDictionary*)notifyStateBlockDic
{
if (!_notifyStateBlockDic) {
_notifyStateBlockDic = [NSMutableDictionary dictionary];
}
return _notifyStateBlockDic;
}
- (NSMutableDictionary*)getServicesStateDic
{
if (!_getServicesStateDic) {
_getServicesStateDic = [NSMutableDictionary dictionary];
}
return _getServicesStateDic;
}
- (NSMutableSet*)notifyCharacteristicSet
{
if (!_notifyCharacteristicSet) {
_notifyCharacteristicSet = [NSMutableSet set];
}
return _notifyCharacteristicSet;
}
- (int)startBLEScanWithId:(NSMutableArray<CBUUID*>*)arrUUID
{
if (self.centralManager.state == CBManagerStatePoweredOn) {
[self.centralManager scanForPeripheralsWithServices:arrUUID options:nil];
return BT_NO_ERROR;
} else {
return BT_ERR_INTERNAL_ERROR;
}
}
- (void)stopBLEScan
{
[self.centralManager stopScan];
}
- (int)getBleState
{
if (self.centralManager) {
return bluetoothState;
}
return 0;
}
- (CBCentralManager *)centralManager {
if (!_centralManager) {
dispatch_main_async_safe(^{
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
});
}
return _centralManager;
}
- (bool)isBleEnabled
{
if (bluetoothState == CBManagerStatePoweredOn) {
return true;
}
return false;
}
- (CBPeripheral*)getDevice:(NSString*)address
{
NSUUID* uuid = [[NSUUID alloc] initWithUUIDString:address];
if (!uuid) {
return nil;
}
NSArray<CBPeripheral*>* arrPeripheral = [self.centralManager retrievePeripheralsWithIdentifiers:@[ uuid ]];
if (arrPeripheral.count == 0) {
NSLog(@"Peripheral is nullptr");
return nil;
}
CBPeripheral* peripheral = arrPeripheral.firstObject;
return peripheral;
}
- (NSString*)getLocalName
{
UIDevice* device = [[UIDevice alloc] init];
return device.name;
}
#pragma mark - gatt client
- (void)registerDeviceId:(NSString*)strDeviceId withAppId:(int32_t)appId
{
NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
[self.diviceIdDic setValue:strDeviceId forKey:strAppId];
}
- (void)closeClient:(int32_t)appId
{
NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
currentPeripheral = [self createGattClientDevice:appId];
if (currentPeripheral == nil) {
return;
}
[self.centralManager cancelPeripheralConnection:currentPeripheral];
[self.diviceIdDic removeObjectForKey:strAppId];
}
- (CBPeripheral*)createGattClientDevice:(int32_t)appId
{
NSString* strAppId = [NSString stringWithFormat:@"%d", appId];
NSString* strDeviceId = [NSString stringWithFormat:@"%@", self.diviceIdDic[strAppId]];
NSUUID* uuid = [[NSUUID alloc] initWithUUIDString:strDeviceId];
if (!uuid) {
return nil;
}
NSArray<CBPeripheral*>* arrPeripheral = [self.centralManager retrievePeripheralsWithIdentifiers:@[ uuid ]];
if (arrPeripheral.count == 0) {
return nil;
}
return arrPeripheral.firstObject;
}
- (int)connect:(int32_t)appId autoConnect:(bool)autoConnect
{
CBPeripheral* peripheral = [self createGattClientDevice:appId];
if (peripheral == nil) {
NSLog(@"Peripheral is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
if (autoConnect) {
[self.arrAutoConnectDivice addObject:peripheral];
}
peripheral.delegate = self;
[self.centralManager connectPeripheral:peripheral options:nil];
currentPeripheral = peripheral;
return BT_NO_ERROR;
}
- (int)disConnect:(int32_t)appId
{
currentPeripheral = [self createGattClientDevice:appId];
if (currentPeripheral == nil) {
NSLog(@"Peripheral is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
[self.centralManager cancelPeripheralConnection:currentPeripheral];
return BT_NO_ERROR;
}
- (void)onServicesDiscoveredCallBack:(CBPeripheral*)peripheral
{
NSString* strCharacterKey = [NSString stringWithFormat:@"%@Character", peripheral.identifier.UUIDString];
NSString* strIncludeServicesKey =
[NSString stringWithFormat:@"%@IncludeServices", peripheral.identifier.UUIDString];
NSString* strDescriptorsKey = [NSString stringWithFormat:@"%@Descriptors", peripheral.identifier.UUIDString];
NSMutableDictionary* characterDic = self.getServicesStateDic[strCharacterKey];
NSMutableDictionary* includeServicesDic = self.getServicesStateDic[strIncludeServicesKey];
NSMutableDictionary* descriptorsDic = self.getServicesStateDic[strDescriptorsKey];
if ([characterDic.allValues containsObject:strNo] || [includeServicesDic.allValues containsObject:strNo] ||
[descriptorsDic.allValues containsObject:strNo]) {
return;
}
[self.getServicesStateDic removeObjectForKey:peripheral.identifier.UUIDString];
if (self.servicesDiscoveredBlock) {
self.servicesDiscoveredBlock(BT_NO_ERROR);
}
}
- (NSArray<CBService*>*)getServices:(int)appId
{
currentPeripheral = [self createGattClientDevice:appId];
return currentPeripheral.services;
}
- (int)discoverServices:(int)appId
{
currentPeripheral = [self createGattClientDevice:appId];
currentPeripheral.delegate = self;
if (currentPeripheral.state == CBPeripheralStateConnected) {
[currentPeripheral discoverServices:nil];
return BT_NO_ERROR;
} else {
return BT_ERR_INTERNAL_ERROR;
}
}
- (CBCharacteristic*)getCurrentCharacteristic:(NSString*)serviceUUID charaUUID:(NSString*)charaUUID
{
CBCharacteristic* currentCharacter = nil;
for (CBService* service in currentPeripheral.services) {
if (![BluetoothUntils IsSameBluetoothUuid:service.UUID.UUIDString right:serviceUUID]) {
continue;
}
for (CBCharacteristic* character in service.characteristics) {
if ([BluetoothUntils IsSameBluetoothUuid:character.UUID.UUIDString right:charaUUID]) {
currentCharacter = character;
break;
}
}
}
return currentCharacter;
}
- (int)RequestNotification:(int)appId
serviceUuid:(CBUUID*)serviceUuid
characterUuid:(CBUUID*)characterUuid
enableNotification:(bool)enableNotification
block:(NotifyCharacterBlock)block
completion:(NotifyStateCompletionBlock)completion
{
currentPeripheral = [self createGattClientDevice:appId];
if (currentPeripheral == nil) {
return BT_ERR_DEVICE_DISCONNECTED;
}
currentPeripheral.delegate = self;
CBCharacteristic* currentCharacter = [self getCurrentCharacteristic:serviceUuid.UUIDString
charaUUID:characterUuid.UUIDString];
if (currentPeripheral.state != CBPeripheralStateConnected) {
return BT_ERR_DEVICE_DISCONNECTED;
}
if (currentCharacter == nil) {
return BT_ERR_GATT_SERVICE_NOT_FOUND;
}
NSString* strKey = BuildNotifyCharacteristicKey(serviceUuid.UUIDString, characterUuid.UUIDString);
BOOL supportNotify = ((currentCharacter.properties & CBCharacteristicPropertyNotify) != 0) ||
((currentCharacter.properties & CBCharacteristicPropertyNotifyEncryptionRequired) != 0);
BOOL supportIndicate = ((currentCharacter.properties & CBCharacteristicPropertyIndicate) != 0) ||
((currentCharacter.properties & CBCharacteristicPropertyIndicateEncryptionRequired) != 0);
if (!supportNotify && !supportIndicate) {
return BT_ERR_API_NOT_SUPPORT;
}
if (currentCharacter.isNotifying == enableNotification) {
[self cacheNotifyBlock:block enable:enableNotification key:strKey];
if (completion) {
completion(BT_NO_ERROR);
}
return BT_NO_ERROR;
}
return [self requestNotifyStateForPeripheral:currentPeripheral
characteristic:currentCharacter
enable:enableNotification
key:strKey
block:block
completion:completion];
}
- (void)setCharacteristicBlock:(id)block forKey:(NSString*)strKey
{
if (block == nil || strKey.length == 0) {
return;
}
@synchronized(self) {
[self.characteristicBlockDic setObject:[block copy] forKey:strKey];
}
}
- (id)characteristicBlockForKey:(NSString*)strKey
{
@synchronized(self) {
return self.characteristicBlockDic[strKey];
}
}
- (void)removeCharacteristicBlockForKey:(NSString*)strKey
{
@synchronized(self) {
[self.characteristicBlockDic removeObjectForKey:strKey];
}
}
- (void)cacheNotifyBlock:(NotifyCharacterBlock)block enable:(BOOL)enable key:(NSString*)strKey
{
@synchronized(self) {
if (enable) {
if (block) {
[self.characteristicBlockDic setObject:[block copy] forKey:strKey];
}
[self.notifyCharacteristicSet addObject:strKey];
return;
}
[self.characteristicBlockDic removeObjectForKey:strKey];
[self.notifyCharacteristicSet removeObject:strKey];
}
}
- (NotifyCharacterBlock)notifyBlockForKey:(NSString*)strKey
{
@synchronized(self) {
if (![self.notifyCharacteristicSet containsObject:strKey]) {
return nil;
}
return self.characteristicBlockDic[strKey];
}
}
- (int)requestNotifyStateForPeripheral:(CBPeripheral*)peripheral
characteristic:(CBCharacteristic*)characteristic
enable:(BOOL)enable
key:(NSString*)strKey
block:(NotifyCharacterBlock)block
completion:(NotifyStateCompletionBlock)completion
{
__block int notifyRet = BT_ERR_INTERNAL_ERROR;
BOOL isMainThreadRequest = [NSThread isMainThread];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NotifyStateBlock stateBlock = ^(CBCharacteristic* chara, int32_t ret) {
if (ret == BT_NO_ERROR && chara.isNotifying != enable) {
notifyRet = BT_ERR_INTERNAL_ERROR;
} else {
notifyRet = ret;
}
if (notifyRet == BT_NO_ERROR) {
[self cacheNotifyBlock:block enable:enable key:strKey];
}
if (completion && (isMainThreadRequest || notifyRet == BT_NO_ERROR)) {
completion(notifyRet);
}
dispatch_semaphore_signal(semaphore);
};
@synchronized(self.notifyStateBlockDic) {
[self.notifyStateBlockDic setObject:[stateBlock copy] forKey:strKey];
}
dispatch_main_async_safe(^{
[peripheral setNotifyValue:enable forCharacteristic:characteristic];
});
if (![NSThread isMainThread]) {
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, NOTIFY_STATE_TIMEOUT_SECONDS * NSEC_PER_SEC);
if (dispatch_semaphore_wait(semaphore, timeout) != 0) {
@synchronized(self.notifyStateBlockDic) {
[self.notifyStateBlockDic removeObjectForKey:strKey];
}
return BT_ERR_INTERNAL_ERROR;
}
} else {
// CoreBluetooth reports the real notification result asynchronously on the main queue.
notifyRet = BT_NO_ERROR;
}
return notifyRet;
}
#pragma mark - delegate
- (void)centralManagerDidUpdateState:(CBCentralManager*)central
{
bluetoothState = central.state;
if (self.updataBleStateBlock) {
self.updataBleStateBlock(bluetoothState);
}
}
- (void)centralManager:(CBCentralManager*)central
didDiscoverPeripheral:(CBPeripheral*)peripheral
advertisementData:(NSDictionary<NSString*, id>*)advertisementData
RSSI:(NSNumber*)RSSI
{
if (self.scanDataBlock) {
self.scanDataBlock(peripheral, advertisementData, RSSI);
}
}
- (void)centralManager:(CBCentralManager*)central didConnectPeripheral:(CBPeripheral*)peripheral
{
if (self.connectStateBlock) {
self.connectStateBlock(BT_NO_ERROR, peripheral.state);
}
}
- (void)centralManager:(CBCentralManager*)central
didFailToConnectPeripheral:(CBPeripheral*)peripheral
error:(NSError*)error
{
if (self.connectStateBlock) {
self.connectStateBlock(BT_ERR_INTERNAL_ERROR, peripheral.state);
}
}
- (void)centralManager:(CBCentralManager*)central
didDisconnectPeripheral:(CBPeripheral*)peripheral
error:(NSError*)error
{
if ([self.arrAutoConnectDivice containsObject:peripheral]) {
[self.centralManager connectPeripheral:peripheral options:nil];
}
if (self.connectStateBlock) {
self.connectStateBlock(BT_NO_ERROR, peripheral.state);
}
}
- (void)peripheral:(CBPeripheral*)peripheral didDiscoverServices:(NSError*)error
{
NSMutableDictionary* characterDic = [NSMutableDictionary dictionary];
NSMutableDictionary* includeServicesDic = [NSMutableDictionary dictionary];
for (CBService* service in peripheral.services) {
[includeServicesDic setValue:strNo forKey:service.UUID.UUIDString];
[characterDic setValue:strNo forKey:service.UUID.UUIDString];
[peripheral discoverIncludedServices:nil forService:service];
[peripheral discoverCharacteristics:nil forService:service];
}
NSString* strCharacterKey = [NSString stringWithFormat:@"%@Character", peripheral.identifier.UUIDString];
NSString* strIncludeServicesKey =
[NSString stringWithFormat:@"%@IncludeServices", peripheral.identifier.UUIDString];
[self.getServicesStateDic setValue:characterDic forKey:strCharacterKey];
[self.getServicesStateDic setValue:includeServicesDic forKey:strIncludeServicesKey];
}
- (void)peripheral:(CBPeripheral*)peripheral
didDiscoverIncludedServicesForService:(CBService*)service
error:(NSError*)error
{
NSString* strCharacterKey = [NSString stringWithFormat:@"%@Character", peripheral.identifier.UUIDString];
NSString* strIncludedServicesKey =
[NSString stringWithFormat:@"%@IncludeServices", peripheral.identifier.UUIDString];
NSMutableDictionary* includedServicesDic = self.getServicesStateDic[strIncludedServicesKey];
NSMutableDictionary* characterDic = self.getServicesStateDic[strCharacterKey];
[includedServicesDic setValue:strYes forKey:service.UUID.UUIDString];
for (CBService* includeService in service.includedServices) {
[includedServicesDic setValue:strNo forKey:includeService.UUID.UUIDString];
[characterDic setValue:strNo forKey:includeService.UUID.UUIDString];
[peripheral discoverIncludedServices:nil forService:includeService];
[peripheral discoverCharacteristics:nil forService:includeService];
}
[self onServicesDiscoveredCallBack:peripheral];
}
- (void)peripheral:(CBPeripheral*)peripheral
didDiscoverCharacteristicsForService:(CBService*)service
error:(NSError*)error
{
NSString* strCharacterKey = [NSString stringWithFormat:@"%@Character", peripheral.identifier.UUIDString];
NSMutableDictionary* characterDic = self.getServicesStateDic[strCharacterKey];
[characterDic setValue:strYes forKey:service.UUID.UUIDString];
NSString* strDescriptorsKey = [NSString stringWithFormat:@"%@Descriptors", peripheral.identifier.UUIDString];
NSMutableDictionary* descriptorsDic = [NSMutableDictionary dictionary];
for (CBCharacteristic* characteristic in service.characteristics) {
[peripheral discoverDescriptorsForCharacteristic:characteristic];
[descriptorsDic setValue:strNo forKey:characteristic.UUID.UUIDString];
}
[self.getServicesStateDic setValue:descriptorsDic forKey:strDescriptorsKey];
[self onServicesDiscoveredCallBack:peripheral];
}
- (void)peripheral:(CBPeripheral*)peripheral
didDiscoverDescriptorsForCharacteristic:(CBCharacteristic*)characteristic
error:(NSError*)error
{
NSString* strDescriptorsKey = [NSString stringWithFormat:@"%@Descriptors", peripheral.identifier.UUIDString];
NSMutableDictionary* descriptorsDic = self.getServicesStateDic[strDescriptorsKey];
[descriptorsDic setValue:strYes forKey:characteristic.UUID.UUIDString];
[self onServicesDiscoveredCallBack:peripheral];
}
- (void)peripheral:(CBPeripheral*)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic*)characteristic
error:(NSError*)error
{
NSString* strKey = [NSString stringWithFormat:@"%@readCharacteristic", characteristic.UUID.UUIDString];
ReadCharacterBlock readCharacterBlock = (ReadCharacterBlock)[self characteristicBlockForKey:strKey];
int state = error ? BT_ERR_INTERNAL_ERROR : BT_NO_ERROR;
if (readCharacterBlock) {
readCharacterBlock(characteristic, state);
}
NSString* notifyKey = BuildNotifyCharacteristicKey(
characteristic.service.UUID.UUIDString, characteristic.UUID.UUIDString);
NotifyCharacterBlock notifyCharacterBlock = [self notifyBlockForKey:notifyKey];
if (notifyCharacterBlock) {
notifyCharacterBlock(characteristic, state);
}
}
- (void)peripheral:(CBPeripheral*)peripheral
didUpdateNotificationStateForCharacteristic:(CBCharacteristic*)characteristic
error:(NSError*)error
{
NSString* notifyKey = BuildNotifyCharacteristicKey(
characteristic.service.UUID.UUIDString, characteristic.UUID.UUIDString);
NotifyStateBlock notifyStateBlock = nil;
@synchronized(self.notifyStateBlockDic) {
notifyStateBlock = self.notifyStateBlockDic[notifyKey];
if (notifyStateBlock) {
[self.notifyStateBlockDic removeObjectForKey:notifyKey];
}
}
if (!notifyStateBlock) {
return;
}
int state = error ? BT_ERR_INTERNAL_ERROR : BT_NO_ERROR;
notifyStateBlock(characteristic, state);
}
- (void)peripheral:(CBPeripheral*)peripheral
didWriteValueForCharacteristic:(CBCharacteristic*)characteristic
error:(nullable NSError*)error
{
NSString* strKey = [NSString stringWithFormat:@"%@writeCharacter", characteristic.UUID.UUIDString];
WriteCharacterBlock writeCharacteristicValueBlock = (WriteCharacterBlock)[self characteristicBlockForKey:strKey];
if (writeCharacteristicValueBlock) {
if (error) {
writeCharacteristicValueBlock(characteristic, BT_ERR_INTERNAL_ERROR);
} else {
writeCharacteristicValueBlock(characteristic, BT_NO_ERROR);
}
}
}
- (void)peripheral:(CBPeripheral*)peripheral didUpdateValueForDescriptor:(CBDescriptor*)descriptor error:(NSError*)error
{
NSString* strKey = [NSString stringWithFormat:@"%@readDescriptor", descriptor.UUID.UUIDString];
ReadDescriptorBlock readDescriptorBlock = (ReadDescriptorBlock)[self characteristicBlockForKey:strKey];
if (readDescriptorBlock) {
if (error) {
readDescriptorBlock(descriptor, BT_ERR_INTERNAL_ERROR);
} else {
readDescriptorBlock(descriptor, BT_NO_ERROR);
}
}
}
- (void)peripheral:(CBPeripheral*)peripheral didWriteValueForDescriptor:(CBDescriptor*)descriptor error:(NSError*)error
{
NSString* strKey = BuildDescriptorOperationKey(descriptor.characteristic.service.UUID.UUIDString,
descriptor.characteristic.UUID.UUIDString, descriptor.UUID.UUIDString, @"writeDescriptor");
WriteDescriptorBlock writeDescriptorBlock = (WriteDescriptorBlock)[self characteristicBlockForKey:strKey];
if (!writeDescriptorBlock) {
return;
}
writeDescriptorBlock(descriptor, error ? BT_ERR_INTERNAL_ERROR : BT_NO_ERROR);
[self removeCharacteristicBlockForKey:strKey];
}
- (int)getReadCharacteristic:(int)appId
serviceUuid:(CBUUID*)serviceUuid
characterUuid:(CBUUID*)characterUuid
data:(ReadCharacterBlock)dataBlock
{
if (!dataBlock) {
return BT_ERR_INTERNAL_ERROR;
}
NSString* strKey = [NSString stringWithFormat:@"%@readCharacteristic", characterUuid.UUIDString];
[self setCharacteristicBlock:dataBlock forKey:strKey];
currentPeripheral = [self createGattClientDevice:appId];
currentPeripheral.delegate = self;
CBCharacteristic* currentCharacter = [self getCurrentCharacteristic:serviceUuid.UUIDString
charaUUID:characterUuid.UUIDString];
if (currentCharacter == nil || currentPeripheral.state != CBPeripheralStateConnected) {
return BT_ERR_INTERNAL_ERROR;
}
if (currentCharacter.properties & CBCharacteristicPropertyRead) {
[currentPeripheral readValueForCharacteristic:currentCharacter];
return BT_NO_ERROR;
}
return BT_ERR_INTERNAL_ERROR;
}
- (int)WriteCharacterCallBackError:(WriteCharacterBlock)block
{
if (block) {
block(nil, BT_ERR_INTERNAL_ERROR);
}
return BT_ERR_INTERNAL_ERROR;
}
- (int)writeCharacteristic:(int)appId
serviceUuid:(CBUUID*)serviceUuid
characterUuid:(CBUUID*)characterUuid
data:(NSData*)data
isOutResponse:(bool)isOutResponse
isSigned:(bool)isSigned
block:(WriteCharacterBlock)block
{
if (currentPeripheral.state != CBPeripheralStateConnected || !block) {
return BT_ERR_INTERNAL_ERROR;
}
NSString* strKey = [NSString stringWithFormat:@"%@writeCharacter", characterUuid.UUIDString];
[self setCharacteristicBlock:block forKey:strKey];
currentPeripheral = [self createGattClientDevice:appId];
currentPeripheral.delegate = self;
CBCharacteristic* currentCharacter = [self getCurrentCharacteristic:serviceUuid.UUIDString
charaUUID:characterUuid.UUIDString];
if (currentCharacter == nil || data == nil) {
return BT_ERR_INTERNAL_ERROR;
}
if (isSigned) {
if (currentCharacter.properties & CBCharacteristicPropertyAuthenticatedSignedWrites) {
[currentPeripheral writeValue:data
forCharacteristic:currentCharacter
type:CBCharacteristicWriteWithoutResponse];
} else {
return BT_ERR_INTERNAL_ERROR;
}
} else if (isOutResponse) {
if (currentCharacter.properties & CBCharacteristicPropertyWriteWithoutResponse) {
[currentPeripheral writeValue:data
forCharacteristic:currentCharacter
type:CBCharacteristicWriteWithoutResponse];
} else {
return BT_ERR_INTERNAL_ERROR;
}
} else {
if (currentCharacter.properties & CBCharacteristicPropertyWrite) {
[currentPeripheral writeValue:data
forCharacteristic:currentCharacter
type:CBCharacteristicWriteWithResponse];
} else {
return BT_ERR_INTERNAL_ERROR;
}
}
return BT_NO_ERROR;
}
- (int)getReadDescriptor:(int)appId
serviceUuid:(CBUUID*)serviceUuid
characterUuid:(CBUUID*)characterUuid
descriptorUuid:(CBUUID*)descriptorUuid
data:(ReadDescriptorBlock)dataBlock
{
if (currentPeripheral.state != CBPeripheralStateConnected || !dataBlock) {
return BT_ERR_INTERNAL_ERROR;
}
NSString* strKey = [NSString stringWithFormat:@"%@readDescriptor", descriptorUuid.UUIDString];
[self setCharacteristicBlock:dataBlock forKey:strKey];
CBDescriptor* currentDescriptor = nil;
currentPeripheral = [self createGattClientDevice:appId];
currentPeripheral.delegate = self;
CBCharacteristic* currentCharacter = [self getCurrentCharacteristic:serviceUuid.UUIDString
charaUUID:characterUuid.UUIDString];
for (CBDescriptor* des in currentCharacter.descriptors) {
if ([BluetoothUntils IsSameBluetoothUuid:descriptorUuid.UUIDString right:des.UUID.UUIDString]) {
currentDescriptor = des;
break;
}
}
if (currentDescriptor == nil) {
return BT_ERR_INTERNAL_ERROR;
}
[currentPeripheral readValueForDescriptor:currentDescriptor];
return BT_NO_ERROR;
}
- (int)writeDescriptor:(int)appId
serviceUuid:(CBUUID*)serviceUuid
characterUuid:(CBUUID*)characterUuid
descriptorUuid:(CBUUID*)descriptorUuid
data:(NSData*)data
block:(WriteDescriptorBlock)block
{
currentPeripheral = [self createGattClientDevice:appId];
if (currentPeripheral == nil || currentPeripheral.state != CBPeripheralStateConnected || data == nil || !block) {
return BT_ERR_INTERNAL_ERROR;
}
currentPeripheral.delegate = self;
CBCharacteristic* currentCharacter = [self getCurrentCharacteristic:serviceUuid.UUIDString
charaUUID:characterUuid.UUIDString];
if (currentCharacter == nil) {
return BT_ERR_INTERNAL_ERROR;
}
CBDescriptor* currentDescriptor = nil;
for (CBDescriptor* descriptor in currentCharacter.descriptors) {
if ([BluetoothUntils IsSameBluetoothUuid:descriptor.UUID.UUIDString right:descriptorUuid.UUIDString]) {
currentDescriptor = descriptor;
break;
}
}
if (currentDescriptor == nil) {
return BT_ERR_INTERNAL_ERROR;
}
NSString* strKey = BuildDescriptorOperationKey(serviceUuid.UUIDString,
characterUuid.UUIDString, descriptorUuid.UUIDString, @"writeDescriptor");
[self setCharacteristicBlock:block forKey:strKey];
[currentPeripheral writeValue:data forDescriptor:currentDescriptor];
return BT_NO_ERROR;
}
@end