Commit 828eb02a authored by Max Model's avatar Max Model

ios fix

parent 0dda0a55
Pipeline #270 failed with stages
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
042C1F762380175A00B86911 /* EADSessionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 042C1F742380175A00B86911 /* EADSessionController.m */; };
69CA06071CC43C2900AF6479 /* RCTBluetoothSerial.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 69CA06061CC43C2900AF6479 /* RCTBluetoothSerial.h */; };
69CA06091CC43C2900AF6479 /* RCTBluetoothSerial.m in Sources */ = {isa = PBXBuildFile; fileRef = 69CA06081CC43C2900AF6479 /* RCTBluetoothSerial.m */; };
69CA06161CC49D5E00AF6479 /* BLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 69CA06101CC49D5E00AF6479 /* BLE.m */; };
69CA06171CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 69CA06131CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
69CA06011CC43C2900AF6479 /* Copy Files */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
69CA06071CC43C2900AF6479 /* RCTBluetoothSerial.h in Copy Files */,
);
name = "Copy Files";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
041CD6B2238010160016A1C2 /* ExternalAccessory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExternalAccessory.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/ExternalAccessory.framework; sourceTree = DEVELOPER_DIR; };
042C1F742380175A00B86911 /* EADSessionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EADSessionController.m; sourceTree = "<group>"; };
042C1F752380175A00B86911 /* EADSessionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EADSessionController.h; sourceTree = "<group>"; };
69CA06031CC43C2900AF6479 /* libRCTBluetoothSerial.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBluetoothSerial.a; sourceTree = BUILT_PRODUCTS_DIR; };
69CA06061CC43C2900AF6479 /* RCTBluetoothSerial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBluetoothSerial.h; sourceTree = "<group>"; };
69CA06081CC43C2900AF6479 /* RCTBluetoothSerial.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTBluetoothSerial.m; sourceTree = "<group>"; };
69CA060F1CC49D5E00AF6479 /* BLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLE.h; sourceTree = "<group>"; };
69CA06101CC49D5E00AF6479 /* BLE.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLE.m; sourceTree = "<group>"; };
69CA06111CC49D5E00AF6479 /* BLEDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLEDefines.h; sourceTree = "<group>"; };
69CA06121CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CBPeripheral+BTSExtensions.h"; sourceTree = "<group>"; };
69CA06131CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CBPeripheral+BTSExtensions.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
69CA06001CC43C2900AF6479 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
041CD6B1238010160016A1C2 /* Frameworks */ = {
isa = PBXGroup;
children = (
041CD6B2238010160016A1C2 /* ExternalAccessory.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
69CA05FA1CC43C2900AF6479 = {
isa = PBXGroup;
children = (
69CA06051CC43C2900AF6479 /* RCTBluetoothSerial */,
69CA06041CC43C2900AF6479 /* Products */,
041CD6B1238010160016A1C2 /* Frameworks */,
);
sourceTree = "<group>";
};
69CA06041CC43C2900AF6479 /* Products */ = {
isa = PBXGroup;
children = (
69CA06031CC43C2900AF6479 /* libRCTBluetoothSerial.a */,
);
name = Products;
sourceTree = "<group>";
};
69CA06051CC43C2900AF6479 /* RCTBluetoothSerial */ = {
isa = PBXGroup;
children = (
042C1F752380175A00B86911 /* EADSessionController.h */,
042C1F742380175A00B86911 /* EADSessionController.m */,
69CA060F1CC49D5E00AF6479 /* BLE.h */,
69CA06101CC49D5E00AF6479 /* BLE.m */,
69CA06111CC49D5E00AF6479 /* BLEDefines.h */,
69CA06121CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.h */,
69CA06131CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.m */,
69CA06061CC43C2900AF6479 /* RCTBluetoothSerial.h */,
69CA06081CC43C2900AF6479 /* RCTBluetoothSerial.m */,
);
path = RCTBluetoothSerial;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
69CA06021CC43C2900AF6479 /* RCTBluetoothSerial */ = {
isa = PBXNativeTarget;
buildConfigurationList = 69CA060C1CC43C2900AF6479 /* Build configuration list for PBXNativeTarget "RCTBluetoothSerial" */;
buildPhases = (
69CA05FF1CC43C2900AF6479 /* Sources */,
69CA06001CC43C2900AF6479 /* Frameworks */,
69CA06011CC43C2900AF6479 /* Copy Files */,
);
buildRules = (
);
dependencies = (
);
name = RCTBluetoothSerial;
productName = RCTBluetoothSerial;
productReference = 69CA06031CC43C2900AF6479 /* libRCTBluetoothSerial.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
69CA05FB1CC43C2900AF6479 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Nuttawut Malee";
TargetAttributes = {
69CA06021CC43C2900AF6479 = {
CreatedOnToolsVersion = 7.3;
};
};
};
buildConfigurationList = 69CA05FE1CC43C2900AF6479 /* Build configuration list for PBXProject "RCTBluetoothSerial" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 69CA05FA1CC43C2900AF6479;
productRefGroup = 69CA06041CC43C2900AF6479 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
69CA06021CC43C2900AF6479 /* RCTBluetoothSerial */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
69CA05FF1CC43C2900AF6479 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
69CA06091CC43C2900AF6479 /* RCTBluetoothSerial.m in Sources */,
69CA06161CC49D5E00AF6479 /* BLE.m in Sources */,
69CA06171CC49D5E00AF6479 /* CBPeripheral+BTSExtensions.m in Sources */,
042C1F762380175A00B86911 /* EADSessionController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
69CA060A1CC43C2900AF6479 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../ios/Pods/Headers/Public/**";
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
69CA060B1CC43C2900AF6479 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../ios/Pods/Headers/Public/**";
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
69CA060D1CC43C2900AF6479 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../ios/Pods/Headers/Public/**";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
69CA060E1CC43C2900AF6479 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../ios/Pods/Headers/Public/**";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
69CA05FE1CC43C2900AF6479 /* Build configuration list for PBXProject "RCTBluetoothSerial" */ = {
isa = XCConfigurationList;
buildConfigurations = (
69CA060A1CC43C2900AF6479 /* Debug */,
69CA060B1CC43C2900AF6479 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
69CA060C1CC43C2900AF6479 /* Build configuration list for PBXNativeTarget "RCTBluetoothSerial" */ = {
isa = XCConfigurationList;
buildConfigurations = (
69CA060D1CC43C2900AF6479 /* Debug */,
69CA060E1CC43C2900AF6479 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 69CA05FB1CC43C2900AF6479 /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69CA06021CC43C2900AF6479"
BuildableName = "libRCTBluetoothSerial.a"
BlueprintName = "RCTBluetoothSerial"
ReferencedContainer = "container:RCTBluetoothSerial.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69CA06021CC43C2900AF6479"
BuildableName = "libRCTBluetoothSerial.a"
BlueprintName = "RCTBluetoothSerial"
ReferencedContainer = "container:RCTBluetoothSerial.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "69CA06021CC43C2900AF6479"
BuildableName = "libRCTBluetoothSerial.a"
BlueprintName = "RCTBluetoothSerial"
ReferencedContainer = "container:RCTBluetoothSerial.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>RCTBluetoothSerial.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
</dict>
</plist>
/*
Edited by Nuttawut Malee on 10.11.18
Copyright (c) 2013 RedBearLab
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <CoreBluetooth/CoreBluetooth.h>
#else
#import <IOBluetooth/IOBluetooth.h>
#endif
#import "CBPeripheral+BTSExtensions.h"
typedef void (^CentralManagerDiscoverPeripheralsCallback) (NSMutableArray *peripherals);
/*!
* BLE delegate event to send data
* to delegate class.
*/
@protocol BLEDelegate
@required
/*!
* @method didPowerOn
*
* @discussion Delegate bluetooth enabled.
*
*/
- (void)didPowerOn;
/*!
* @method didPowerOff
*
* @discussion Delegate bluetooth disabled.
*
*/
- (void)didPowerOff;
/*!
* @method didError
*
* @param error The error that will be delegated to delegate class.
*
*/
- (void)didError:(NSError *)error;
/*!
* @method didConnect
*
* @param peripheral The connected peripheral.
*
*/
- (void)didConnect:(CBPeripheral *) peripheral;
/*!
* @method didFailToConnect
*
* @param peripheral The connected peripheral.
*
*/
- (void)didFailToConnect:(CBPeripheral *) peripheral;
/*!
* @method didConnectionLost
*
* @param peripheral The connected peripheral.
*
*/
- (void)didConnectionLost:(CBPeripheral *) peripheral;
/*!
* @method didReceiveData:length:
*
* @param uuid The UUID string of the peripheral.
* @param data The received data from peripheral buffer.
* @param length The length of received data.
*
*/
- (void)didReceiveData:(NSString *)uuid data:(unsigned char *) data length:(NSInteger) length;
@end
/*!
* BLE wrapper class that implement
* common central manager and peripheral instance.
*/
@interface BLE : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate>
/*!
* The delegate object that will receive BLE central events.
*/
@property (nonatomic, assign) id<BLEDelegate> delegate;
/*!
* Core bluetooth's Central manager, for implementing central role.
*/
@property (strong, nonatomic) CBCentralManager *manager;
/*!
* Peripherals that are nearby (sorted descending by RSSI values).
*/
@property (weak, nonatomic, readonly) NSArray *peripherals;
/*!
* List of scanned peripherals.
*/
@property (strong, nonatomic) NSMutableArray *scannedPeripherals;
/*!
* The active peripherals that each has been paired and connected.
*/
@property (nonatomic, copy) NSMutableDictionary *activePeripherals;
/*!
* CBCentralManager's state updated by centralManagerDidUpdateState:
*/
@property(nonatomic) CBCentralManagerState cbCentralManagerState;
/*!
* Threshould to stop scanning for peripherals.
* When the number of discovered peripherals exceeds this value, scanning will be
* stopped even before the scan-interval.
*/
@property (assign, nonatomic) NSUInteger peripheralsCountToStop;
/*!
* Indicates if central manager is ready for core bluetooth tasks. KVO observable.
*/
@property (assign, nonatomic, readonly, getter = isCentralReady) BOOL centralReady;
/*!
* Available BLE services, read and write characteristics.
*/
@property (strong, nonatomic) NSDictionary *bleServices;
/*!
* Completion block for peripheral scanning.
*/
@property (copy, nonatomic) CentralManagerDiscoverPeripheralsCallback scanBlock;
/*!
* KVO for centralReady and centralNotReadyReason
*/
+ (NSSet *)keyPathsForValuesAffectingCentralReady;
+ (NSSet *)keyPathsForValuesAffectingCentralNotReadyReason;
/*!
* @method isConnected
*
* @param uuid
*
* @discussion Indicates selected peripheral connection status.
*
*/
- (BOOL)isConnected:(NSString *)uuid;
/*!
* @method peripheralToDictionary
*
* @param peripheral
*
* @discussion Get NSMutableDictionary info of a peripheral.
*
*/
- (NSMutableDictionary *)peripheralToDictionary:(CBPeripheral *)peripheral;
/*!
* @method readActivePeripheralRSSI
*
* @param uuid CBPeripheral id.
*
* @discussion Retrieves and delegate current RSSI of current
* active peripheral that connected to central manager.
*
*/
- (void)readActivePeripheralRSSI:(NSString *)uuid;
/*!
* @method enableReadNotification
*
* @param peripheral
*
* @discussion Notify peripheral read for a certain characteristic.
*/
- (void)enableReadNotification:(CBPeripheral *)peripheral;
/*!
* @method read
*
* @param uuid Id of one of the active peripherals.
*
* @discussion Read value from active peripheral
* for a certain characteristic.
*/
- (void)read:(NSString *)uuid;
/*!
* @method write
*
* @param uuid Id of one of the active peripherals.
* @param data Data to be written to an active peripheral.
*
* @discussion Write value to active peripheral
* for a certain characteristic.
*
*/
- (void)write:(NSString *)uuid data:(NSData *)data;
/*!
* @method scanForPeripheralsByInterval
*
* @param interval Interval by which scan will be stopped.
* @param callback Completion block will be called after
* <i>interval</i> with nearby peripherals.
*
* @discussion Scans for nearby peripherals
* and fills the - NSArray *peripherals.
* Scan will be stoped after input interaval.
*
*/
- (void)scanForPeripheralsByInterval:(NSUInteger)interval
completion:(CentralManagerDiscoverPeripheralsCallback)callback;
/*!
* @method stopScanForPeripheral
*
* @discussion Stops ongoing scan proccess
*
*/
- (void)stopScanForPeripherals;
/*!
* @method connectToPeripheral
*
* @param peripheral
*
* @discussion Connect to certain peripheral
* and assign activePeripheral to it.
*
*/
- (void)connectToPeripheral:(CBPeripheral *)peripheral;
/*!
* @method disconnectFromPeripheral
*
* @param peripheral
*
*/
- (void)disconnectFromPeripheral:(CBPeripheral *)peripheral;
/*!
* @method centralManagerSetup
*
* @discussion Request bluetooth enable settings.
*
*/
- (void)centralManagerSetup;
/*!
* @method getActivePeripheral
*
* @discussion Get active peripheral from uuid or the first connected one.
*
*/
- (CBPeripheral *)getActivePeripheral:(NSString *)uuid;
/*!
* @method validateServices
*
* @discussion Validate service object to contain certain keys.
*/
- (BOOL)validateServices:(NSArray *)services;
/*!
* @method servicesArrayToDictionary
*
* @discussion Convert services array to dictionary; key is service.
*/
- (NSDictionary *)servicesArrayToDictionary:(NSArray *)services;
/*!
* @method servicesDictionaryToArray
*
* @discussion Convert services dictionary to array.
*/
- (NSArray *)servicesDictionaryToArray:(NSDictionary *)services;
/*!
* @method getDefaultServices
*
* @discussion Get default BLE service array from BLEDefines.h.
*/
- (NSArray *)getDefaultServices;
/*!
* @method includeDefaultServices.
*
* @discussion Include default BLE service array from BLEDefines.h into services array.
*/
- (NSArray *)includeDefaultServices:(NSArray *)services;
@end
/*
Edited by Nuttawut Malee on 10.11.18
Copyright (c) 2013 RedBearLab
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import "BLE.h"
#import "BLEDefines.h"
@implementation BLE
static const int MAX_BUFFER_LENGTH = 100;
/**
* Default services.
*/
NSDictionary *redBearLabsService;
NSDictionary *adafruitService;
NSDictionary *lairdService;
NSDictionary *blueGigaService;
NSDictionary *rongtaService;
NSDictionary *posnetService;
/*----------------------------------------------------*/
#pragma mark - Lifecycle -
/*----------------------------------------------------*/
- (instancetype)init
{
self = [super init];
if (self) {
_activePeripherals = [NSMutableDictionary dictionary];
_scannedPeripherals = [NSMutableArray new];
_peripheralsCountToStop = NSUIntegerMax;
redBearLabsService = @{@"name": @"Red Bear Labs Service",
@"service": @RBL_SERVICE_UUID,
@"read": @RBL_CHAR_TX_UUID,
@"write": @RBL_CHAR_RX_UUID};
adafruitService = @{@"name": @"Adafruit Service",
@"service": @ADAFRUIT_SERVICE_UUID,
@"read": @ADAFRUIT_CHAR_TX_UUID,
@"write": @ADAFRUIT_CHAR_RX_UUID};
lairdService = @{@"name": @"Laird Service",
@"service": @LAIRD_SERVICE_UUID,
@"read": @LAIRD_CHAR_TX_UUID,
@"write": @LAIRD_CHAR_RX_UUID};
blueGigaService = @{@"name": @"Blue Giga Service",
@"service": @ADAFRUIT_SERVICE_UUID,
@"read": @ADAFRUIT_CHAR_TX_UUID,
@"write": @ADAFRUIT_CHAR_RX_UUID};
rongtaService = @{@"name": @"Rongta Service",
@"service": @RONGTA_SERVICE_UUID,
@"read": @RONGTA_CHAR_TX_UUID,
@"write": @RONGTA_CHAR_RX_UUID};
posnetService = @{@"name": @"POSNET Service",
@"service": @POSNET_SERVICE_UUID,
@"read": @POSNET_CHAR_TX_UUID,
@"write": @POSNET_CHAR_RX_UUID};
_bleServices = [self servicesArrayToDictionary:[self getDefaultServices]];
_manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerOptionShowPowerAlertKey]];
}
return self;
}
/*----------------------------------------------------*/
#pragma mark - Getter/Setter -
/*----------------------------------------------------*/
- (BOOL)isCentralReady
{
return (self.manager.state == CBCentralManagerStatePoweredOn);;
}
- (NSArray *)peripherals
{
// Sorting peripherals by RSSI values
NSArray *sortedArray = [_scannedPeripherals sortedArrayUsingComparator:^NSComparisonResult(CBPeripheral *a, CBPeripheral *b) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return a.RSSI < b.RSSI;
#pragma clang diagnostic pop
}];
return sortedArray;
}
/*----------------------------------------------------*/
#pragma mark - KVO -
/*----------------------------------------------------*/
+ (NSSet *)keyPathsForValuesAffectingCentralReady
{
return [NSSet setWithObject:@"cbCentralManagerState"];
}
+ (NSSet *)keyPathsForValuesAffectingCentralNotReadyReason
{
return [NSSet setWithObject:@"cbCentralManagerState"];
}
/*----------------------------------------------------*/
#pragma mark - Public Methods -
/*----------------------------------------------------*/
- (NSMutableDictionary *)peripheralToDictionary:(CBPeripheral *)peripheral
{
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSString *uuid = peripheral.identifier.UUIDString;
NSString *name = peripheral.name;
NSNumber *rssi = peripheral.btsAdvertisementRSSI;
[result setObject:uuid forKey:@"uuid"];
[result setObject:uuid forKey:@"id"];
if (!name) {
name = [result objectForKey:@"uuid"];
}
[result setObject:name forKey:@"name"];
if (rssi) {
[result setObject:rssi forKey:@"rssi"];
}
return result;
}
- (void)readActivePeripheralRSSI:(NSString *)uuid
{
NSMutableDictionary *dict = [self getFirstPeripheralDictionary:uuid];
if (dict) {
CBPeripheral *peripheral = [dict objectForKey:@"peripheral"];
if (peripheral) {
[peripheral readRSSI];
}
}
}
- (void)enableReadNotification:(CBPeripheral *)peripheral
{
NSMutableDictionary *activePeripheral = [self.activePeripherals objectForKey:peripheral.identifier.UUIDString];
if (!activePeripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBUUID *serviceUUID = [activePeripheral objectForKey:@"service"];
CBService *service = [self findServiceFromUUID:serviceUUID peripheral:peripheral];
if (!service) {
NSString *message = [NSString stringWithFormat:@"Could not find service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_service" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBUUID *readUUID = [activePeripheral objectForKey:@"read"];
CBCharacteristic *characteristic = [self findCharacteristicFromUUID:readUUID service:service];
if (!characteristic) {
NSString *message = [NSString stringWithFormat:
@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:readUUID],
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_characteristic" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
- (BOOL)isConnected:(NSString *)uuid
{
NSMutableDictionary *dict = [self getFirstPeripheralDictionary:uuid];
if (dict) {
return (BOOL)[dict valueForKey:@"connected"];
}
return FALSE;
}
- (void)read:(NSString *)uuid
{
NSMutableDictionary *activePeripheral = [self getFirstPeripheralDictionary:uuid];
if (!activePeripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", uuid];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBPeripheral *peripheral = [activePeripheral objectForKey:@"peripheral"];
if (!peripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", uuid];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBUUID *serviceUUID = [activePeripheral objectForKey:@"service"];
CBService *service = [self findServiceFromUUID:serviceUUID peripheral:peripheral];
if (!service) {
NSString *message = [NSString stringWithFormat:
@"Could not find service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_service" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBUUID *readUUID = [activePeripheral objectForKey:@"read"];
CBCharacteristic *characteristic = [self findCharacteristicFromUUID:readUUID service:service];
if (!characteristic) {
NSString *message = [NSString stringWithFormat:
@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:readUUID],
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_characteristic" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
[peripheral readValueForCharacteristic:characteristic];
}
- (void)write:(NSString *)uuid data:(NSData *)data
{
NSMutableDictionary *activePeripheral = [self getFirstPeripheralDictionary:uuid];
if (!activePeripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", uuid];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBPeripheral *peripheral = [activePeripheral objectForKey:@"peripheral"];
if (!peripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", uuid];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
NSLog(@"Write data to peripheral with UUID %@", uuid);
NSInteger dataLength = data.length;
NSData *buffer;
CBUUID *serviceUUID = [activePeripheral objectForKey:@"service"];
CBUUID *writeUUID = [activePeripheral objectForKey:@"write"];
for (int i = 0; i < dataLength; i += MAX_BUFFER_LENGTH) {
NSInteger remainLength = dataLength - i;
NSInteger bufferLength = (remainLength > MAX_BUFFER_LENGTH) ? MAX_BUFFER_LENGTH : remainLength;
buffer = [data subdataWithRange:NSMakeRange(i, bufferLength)];
NSLog(@"Buffer data %li %i %@", (long)remainLength, i, [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding]);
[self writeValue:serviceUUID characteristicUUID:writeUUID peripheral:peripheral data:buffer];
}
}
- (void)scanForPeripheralsByInterval:(NSUInteger)interval completion:(CentralManagerDiscoverPeripheralsCallback)callback
{
if (!self.isCentralReady) {
NSString *message = [NSString stringWithFormat:
@"CoreBluetooth not correctly initialized! State = %ld (%@)",
(long)self.manager.state,
[self centralManagerStateToString:self.manager.state]];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_bluetooth_initialized" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
callback([NSMutableArray new]);
return;
}
self.scanBlock = callback;
[self scanForPeripheralsByServices];
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(stopScanForPeripherals)
object:nil];
[self performSelector:@selector(stopScanForPeripherals)
withObject:nil
afterDelay:interval];
}
- (void)stopScanForPeripherals
{
[self.manager stopScan];
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(stopScanForPeripherals)
object:nil];
NSLog(@"Stopped Scanning");
NSLog(@"Known peripherals : %lu", (unsigned long)[self.peripherals count]);
[self printKnownPeripherals];
if (self.scanBlock) {
self.scanBlock(self.scannedPeripherals);
}
self.scanBlock = nil;
}
- (void)connectToPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Connecting to peripheral with UUID : %@", peripheral.identifier.UUIDString);
CBPeripheral *activePeripheral = [peripheral copy];
activePeripheral.delegate = self;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:[NSNumber numberWithBool:FALSE] forKey:@"connected"];
[dict setObject:activePeripheral forKey:@"peripheral"];
[dict setObject:@"" forKey:@"service"];
[dict setObject:@"" forKey:@"read"];
[dict setObject:@"" forKey:@"write"];
if ([self.activePeripherals count] <= 0) {
[dict setValue:[NSNumber numberWithBool:TRUE] forKey:@"first"];
} else {
[dict setValue:[NSNumber numberWithBool:FALSE] forKey:@"first"];
}
[self.activePeripherals setObject:dict forKey:activePeripheral.identifier.UUIDString];
[self.manager connectPeripheral:activePeripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
}
- (void)disconnectFromPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Disconnecting peripheral with UUID : %@", peripheral.identifier.UUIDString);
[self.manager cancelPeripheralConnection:peripheral];
}
- (void)centralManagerSetup
{
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerOptionShowPowerAlertKey]];
}
- (CBPeripheral *)getActivePeripheral:(NSString *)uuid
{
NSMutableDictionary *dict = [self getFirstPeripheralDictionary:uuid];
if (dict) {
return (CBPeripheral *)[dict objectForKey:@"peripheral"];
}
return nil;
}
- (NSArray *)getDefaultServices
{
return @[redBearLabsService, adafruitService, lairdService, blueGigaService, rongtaService, posnetService];
}
- (NSArray *)includeDefaultServices:(NSArray *)services
{
NSMutableSet *mergedSet = [NSMutableSet setWithArray:services];
[mergedSet unionSet:[NSSet setWithArray:[self getDefaultServices]]];
NSArray *merged = [mergedSet allObjects];
return merged;
}
- (BOOL)validateServices:(NSArray *)services
{
if ([services isKindOfClass:[NSNull class]] | ([services count] <= 0) | (services == nil)) {
return TRUE;
}
for (NSDictionary *service in services) {
NSString *s = [service objectForKey:@"service"];
NSString *r = [service objectForKey:@"read"];
NSString *w = [service objectForKey:@"write"];
if ([self validateCBUUIDString:s] & [self validateCBUUIDString:r] & [self validateCBUUIDString:w]) {
continue;
}
return FALSE;
}
return TRUE;
}
- (NSDictionary *)servicesArrayToDictionary:(NSArray *)services
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if ([services count] > 0) {
for (NSDictionary *s in services) {
NSMutableDictionary *obj = [[NSMutableDictionary alloc] initWithDictionary:s];
NSString *service = [obj objectForKey:@"service"];
[dict setObject:obj forKey:service];
}
}
return dict;
}
- (NSArray *)servicesDictionaryToArray:(NSDictionary *)services
{
NSMutableArray *array = [NSMutableArray array];
if ([services count] > 0) {
NSArray *keys = [services allKeys];
for (NSString *key in keys) {
NSMutableDictionary *service = [[NSMutableDictionary alloc] initWithDictionary:[services objectForKey:key]];
[service setObject:key forKey:@"service"];
[array addObject:service];
}
}
return array;
}
/*----------------------------------------------------*/
#pragma mark - Private Methods -
/*----------------------------------------------------*/
-(void)scanForPeripheralsByServices
{
// Clear all peripherals
[self.scannedPeripherals removeAllObjects];
#if TARGET_OS_IPHONE
NSMutableArray *services = [[NSMutableArray alloc] init];
if ([self.bleServices count] > 0) {
NSArray *keys = [self.bleServices allKeys];
for (NSString *key in keys) {
[services addObject:[CBUUID UUIDWithString:key]];
}
}
[self.manager scanForPeripheralsWithServices:nil options:nil];
#else
[self.manager scanForPeripheralsWithServices:nil options:nil];
#endif
// NSLog(@"Scan for peripherals with services");
}
- (NSString *)centralManagerStateToString:(int)state
{
switch(state) {
case CBCentralManagerStateUnknown:
return @"State unknown (CBCentralManagerStateUnknown)";
case CBCentralManagerStateResetting:
return @"State resetting (CBCentralManagerStateUnknown)";
case CBCentralManagerStateUnsupported:
return @"State BLE unsupported (CBCentralManagerStateResetting)";
case CBCentralManagerStateUnauthorized:
return @"State unauthorized (CBCentralManagerStateUnauthorized)";
case CBCentralManagerStatePoweredOff:
return @"State BLE powered off (CBCentralManagerStatePoweredOff)";
case CBCentralManagerStatePoweredOn:
return @"State powered up and ready (CBCentralManagerStatePoweredOn)";
default:
return @"State unknown";
}
return @"Unknown state";
}
- (void)writeValue:(CBUUID *)serviceUUID
characteristicUUID:(CBUUID *)characteristicUUID
peripheral:(CBPeripheral *)peripheral
data:(NSData *)data
{
CBService *service = [self findServiceFromUUID:serviceUUID peripheral:peripheral];
if (!service) {
NSString *message = [NSString stringWithFormat:@"Could not find service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_service" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
CBCharacteristic *characteristic = [self findCharacteristicFromUUID:characteristicUUID service:service];
if (!characteristic) {
NSString *message = [NSString stringWithFormat:
@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
[self CBUUIDToString:characteristicUUID],
[self CBUUIDToString:serviceUUID],
peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_characteristic" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
NSLog(@"Write value in ble.m\n");
NSLog(@"Buffer data %li", (long)data.length);
if ((characteristic.properties & CBCharacteristicPropertyWrite) == CBCharacteristicPropertyWrite) {
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} else if ((characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse) == CBCharacteristicPropertyWriteWithoutResponse) {
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}
}
- (BOOL)validateCBUUIDString:(NSString *)CBUUIDString
{
if ([CBUUIDString isKindOfClass:[NSNull class]] | [CBUUIDString isEqualToString:@""] | (CBUUIDString == nil)) {
return FALSE;
}
return (BOOL)[CBUUID UUIDWithString:CBUUIDString];
}
- (CBCharacteristic *)findCharacteristicFromUUID:(CBUUID *)UUID service:(CBService*)service
{
for (int i = 0; i < service.characteristics.count; i++) {
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
if ([self compareCBUUID:c.UUID UUID2:UUID]) {
return c;
}
}
return nil;
}
- (CBService *)findServiceFromUUID:(CBUUID *)UUID peripheral:(CBPeripheral *)peripheral
{
for (int i = 0; i < peripheral.services.count; i++) {
CBService *s = [peripheral.services objectAtIndex:i];
if ([self compareCBUUID:s.UUID UUID2:UUID]) {
return s;
}
}
return nil;
}
- (UInt16)swap:(UInt16)s
{
UInt16 temp = s << 8;
temp |= (s >> 8);
return temp;
}
- (NSString *)CBUUIDToString:(CBUUID *)UUID
{
NSData *data = UUID.data;
if ([data length] == 2) {
const unsigned char *tokenBytes = [data bytes];
return [NSString stringWithFormat:@"%02x%02x", tokenBytes[0], tokenBytes[1]];
} else if ([data length] == 16) {
NSUUID* nsuuid = [[NSUUID alloc] initWithUUIDBytes:[data bytes]];
return [nsuuid UUIDString];
}
return [UUID description];
}
- (UInt16)CBUUIDToInt:(CBUUID *)UUID
{
char b[16];
[UUID.data getBytes:b length:UUID.data.length];
return ((b[0] << 8) | b[1]);
}
- (int)compareCBUUID:(CBUUID *)UUID1 UUID2:(CBUUID *)UUID2
{
char b1[16];
char b2[16];
[UUID1.data getBytes:b1 length:UUID1.data.length];
[UUID2.data getBytes:b2 length:UUID2.data.length];
if (memcmp(b1, b2, UUID1.data.length) == 0) {
return 1;
} else {
return 0;
}
}
- (int)compareCBUUIDToInt:(CBUUID *)UUID1 UUID2:(UInt16)UUID2
{
char b1[16];
[UUID1.data getBytes:b1 length:UUID1.data.length];
UInt16 b2 = [self swap:UUID2];
if (memcmp(b1, (char *)&b2, 2) == 0) {
return 1;
} else {
return 0;
}
}
- (BOOL)UUIDSAreEqual:(NSUUID *)UUID1 UUID2:(NSUUID *)UUID2
{
if ([UUID1.UUIDString isEqualToString:UUID2.UUIDString]) {
return TRUE;
} else {
return FALSE;
}
}
- (CBUUID *)IntToCBUUID:(UInt16)UUID
{
char t[16];
t[0] = ((UUID >> 8) & 0xff); t[1] = (UUID & 0xff);
NSData *data = [[NSData alloc] initWithBytes:t length:16];
return [CBUUID UUIDWithData:data];
}
#if TARGET_OS_IPHONE
//-- no need for iOS
#else
- (BOOL)isLECapableHardware
{
NSString *state = @"";
switch ([self.manager state]) {
case CBCentralManagerStateUnsupported:
state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
break;
case CBCentralManagerStateUnauthorized:
state = @"The app is not authorized to use Bluetooth Low Energy.";
break;
case CBCentralManagerStatePoweredOff:
state = @"Bluetooth is currently powered off.";
break;
case CBCentralManagerStatePoweredOn:
return TRUE;
case CBCentralManagerStateUnknown:
default:
return FALSE;
}
NSLog(@"Central manager state: %@", state);
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:state];
[alert addButtonWithTitle:@"OK"];
[alert setIcon:[[NSImage alloc] initWithContentsOfFile:@"AppIcon"]];
[alert beginSheetModalForWindow:nil modalDelegate:self didEndSelector:nil contextInfo:nil];
return FALSE;
}
#endif
- (void)printKnownPeripherals
{
/*NSLog(@"List of currently known peripherals :");
for (int i = 0; i < self.peripherals.count; i++) {
CBPeripheral *peripheral = [self.peripherals objectAtIndex:i];
NSLog(@"%d | %@", i, peripheral.identifier.UUIDString);
[self printPeripheralInfo:peripheral];
}*/
}
- (void)printPeripheralInfo:(CBPeripheral*)peripheral
{
NSLog(@"------------------------------------");
NSLog(@"Peripheral Info :");
NSLog(@"UUID : %@", peripheral.identifier.UUIDString);
NSLog(@"Name : %@", peripheral.name);
NSLog(@"-------------------------------------");
}
- (NSMutableDictionary *)getFirstPeripheralDictionary:(NSString *)uuid
{
if (([uuid length] <= 0) | [uuid isEqualToString:@""] | [uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
for (NSString *key in self.activePeripherals) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:key]];
if (!dict) {
continue;
}
if ((BOOL)[dict valueForKey:@"first"]) {
return dict;
}
}
return nil;
}
if ([[self.activePeripherals allKeys] containsObject:uuid]) {
return [self.activePeripherals objectForKey:uuid];
}
return nil;
}
/*----------------------------------------------------*/
#pragma mark - Central Manager Delegate -
/*----------------------------------------------------*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
self.cbCentralManagerState = (CBCentralManagerState)central.state;
#if TARGET_OS_IPHONE
NSString *state = [self centralManagerStateToString:central.state];
NSLog(@"Status of CoreBluetooth central manager changed %ld (%@)", (long)central.state, state);
if (self.isCentralReady) {
[[self delegate] didPowerOn];
} else {
[[self delegate] didPowerOff];
if ([self.activePeripherals count] > 0) {
for (NSString *key in self.activePeripherals) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:key]];
if (!dict) {
continue;
}
if ((BOOL)[dict valueForKey:@"connected"]) {
CBPeripheral *peripheral = [dict objectForKey:@"peripheral"];
[[self delegate] didConnectionLost:peripheral];
}
}
}
}
#else
[self isLECapableHardware];
#endif
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Connected to %@ successful", peripheral.identifier.UUIDString);
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:peripheral.identifier.UUIDString]];
if (dict) {
[dict setObject:peripheral forKey:@"peripheral"];
[self.activePeripherals setObject:dict forKey:peripheral.identifier.UUIDString];
}
[peripheral discoverServices:nil];
}
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
error:(NSError *)error
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:peripheral.identifier.UUIDString]];
if (dict) {
CBPeripheral *activePeripheral = [dict objectForKey:@"peripheral"];
activePeripheral.delegate = nil;
[self.activePeripherals removeObjectForKey:peripheral.identifier.UUIDString];
}
NSLog(@"Failed to connect to %@", peripheral.identifier.UUIDString);
if (error) {
NSString *message = [error localizedDescription];
NSLog(@"%@", message);
[[self delegate] didError:error];
}
[[self delegate] didFailToConnect:peripheral];
}
- (void)centralManager:(CBCentralManager *)central
didDisconnectPeripheral:(CBPeripheral *)peripheral
error:(NSError *)error
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:peripheral.identifier.UUIDString]];
if (dict) {
CBPeripheral *activePeripheral = [dict objectForKey:@"peripheral"];
activePeripheral.delegate = nil;
[self.activePeripherals removeObjectForKey:peripheral.identifier.UUIDString];
}
NSLog(@"Disconnected to %@ successful", peripheral.identifier.UUIDString);
if (error) {
NSString *message = [error localizedDescription];
NSLog(@"%@", message);
[[self delegate] didError:error];
}
[[self delegate] didConnectionLost:peripheral];
}
-(void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI
{
if (!self.scannedPeripherals) {
// Initiate peripherals with a new peripheral
self.scannedPeripherals = [[NSMutableArray alloc] initWithObjects:peripheral, nil];
} else {
// Replace a duplicate peripheral
for (int i = 0; i < self.scannedPeripherals.count; i++) {
CBPeripheral *p = [self.scannedPeripherals objectAtIndex:i];
[p bts_setAdvertisementData:advertisementData RSSI:RSSI];
if ((p.identifier == NULL) || (peripheral.identifier) == NULL) {
continue;
}
if ([self UUIDSAreEqual:p.identifier UUID2:peripheral.identifier]) {
[self.scannedPeripherals replaceObjectAtIndex:i withObject:peripheral];
NSLog(@"Updating duplicate UUID (%@) peripheral", peripheral.identifier.UUIDString);
return;
}
}
// Add a new peripheral
[self.scannedPeripherals addObject:peripheral];
// NSLog(@"Adding new UUID (%@) peripheral", peripheral.identifier.UUIDString);
}
// NSLog(@"didDiscoverPeripheral");
if ([self.scannedPeripherals count] >= self.peripheralsCountToStop) {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(stopScanForPeripherals)
object:nil];
[self stopScanForPeripherals];
}
}
/*----------------------------------------------------*/
#pragma mark - Peripheral Delegate -
/*----------------------------------------------------*/
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error
{
if (error) {
NSString *message = @"Characteristic discovery unsuccessful!";
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_characteristic_discovery" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
NSLog(@"Characteristics of service with UUID : %@ found\n", [self CBUUIDToString:service.UUID]);
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:peripheral.identifier.UUIDString]];
if (dict) {
CBPeripheral *activePeripheral = [dict objectForKey:@"peripheral"];
if (activePeripheral) {
[self enableReadNotification:activePeripheral];
[[self delegate] didConnect:activePeripheral];
[dict setValue:[NSNumber numberWithBool:TRUE] forKey:@"connected"];
[self.activePeripherals setObject:dict forKey:peripheral.identifier.UUIDString];
NSLog(@"Connection with %@ completed", peripheral.identifier.UUIDString);
return;
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
if (error) {
NSString *message = @"Update value for characteristic unsuccessful!";
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_characteristic_update" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
NSMutableDictionary *activePeripheral = [self getFirstPeripheralDictionary:peripheral.identifier.UUIDString];
if (!activePeripheral) {
NSString *message = [NSString stringWithFormat:@"Could not find active peripheral with UUID %@", peripheral.identifier.UUIDString];
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_peripheral" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
static unsigned char buffer[512];
NSInteger dataLength;
CBPeripheral *readUUID = [activePeripheral objectForKey:@"read"];
if ([characteristic.UUID isEqual:readUUID]) {
dataLength = characteristic.value.length;
[characteristic.value getBytes:buffer length:dataLength];
[[self delegate] didReceiveData:peripheral.identifier.UUIDString data:buffer length:dataLength];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSString *message = @"Service discovery unsuccessful!";
NSLog(@"%@", message);
NSError *error = [NSError errorWithDomain:@"no_service_discovery" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[[self delegate] didError:error];
return;
}
NSLog(@"Service discovery for %@ successful", peripheral.identifier.UUIDString);
NSMutableDictionary *activePeripheral = [[NSMutableDictionary alloc] initWithDictionary:[self.activePeripherals objectForKey:peripheral.identifier.UUIDString]];
for (CBService *service in peripheral.services) {
NSString *uuid = [self CBUUIDToString:service.UUID];
NSDictionary *dict = [self.bleServices objectForKey:uuid];
if (dict) {
NSString *name = [dict objectForKey:@"name"];
if (name) {
NSLog(@"Discovered service : %@", name);
}
CBUUID *readCharacteristic = [CBUUID UUIDWithString:[dict objectForKey:@"read"]];
CBUUID *writeCharacteristic = [CBUUID UUIDWithString:[dict objectForKey:@"write"]];
if (activePeripheral) {
[activePeripheral setObject:service.UUID forKey:@"service"];
[activePeripheral setObject:readCharacteristic forKey:@"read"];
[activePeripheral setObject:writeCharacteristic forKey:@"write"];
[self.activePeripherals setObject:activePeripheral forKey:peripheral.identifier.UUIDString];
}
[peripheral discoverCharacteristics:@[readCharacteristic, writeCharacteristic] forService:service];
break;
}
}
}
@end
/*
Copyright (c) 2013 RedBearLab
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// BlueGiga Service
#define BLUEGIGA_SERVICE_UUID "1D5688DE-866D-3AA4-EC46-A1BDDB37ECF6"
#define BLUEGIGA_CHAR_TX_UUID "AF20fBAC-2518-4998-9AF7-AF42540731B3"
#define BLUEGIGA_CHAR_RX_UUID "AF20fBAC-2518-4998-9AF7-AF42540731B3"
// RBL Service
#define RBL_SERVICE_UUID "713D0000-503E-4C75-BA94-3148F18D941E"
#define RBL_CHAR_TX_UUID "713D0002-503E-4C75-BA94-3148F18D941E"
#define RBL_CHAR_RX_UUID "713D0003-503E-4C75-BA94-3148F18D941E"
// Adafruit BLE
// http://learn.adafruit.com/getting-started-with-the-nrf8001-bluefruit-le-breakout/adding-app-support
// Adafruit | Nordic's TX and RX are the opposite of RBL. This code uses RBL perspective for naming.
#define ADAFRUIT_SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define ADAFRUIT_CHAR_TX_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define ADAFRUIT_CHAR_RX_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
// Laird Virtual Serial Port (vSP) service for BL600 http://www.lairdtech.com/DownloadAsset.aspx?id=2147489885
#define LAIRD_SERVICE_UUID "569a1101-b87f-490c-92cb-11ba5ea5167c"
#define LAIRD_CHAR_TX_UUID "569a2000-b87f-490c-92cb-11ba5ea5167c"
#define LAIRD_CHAR_RX_UUID "569a2001-b87f-490c-92cb-11ba5ea5167c"
#define RONGTA_SERVICE_UUID "E7810A71-73AE-499D-8C15-FAA9AEF0C3F2"
#define RONGTA_CHAR_TX_UUID "BEF8D6C9-9C21-4C9E-B632-BD58C1009F9F"
#define RONGTA_CHAR_RX_UUID "BEF8D6C9-9C21-4C9E-B632-BD58C1009F9F"
#define POSNET_SERVICE_UUID "53544D54-4552-494F-5345-525631303030"
#define POSNET_CHAR_TX_UUID "53544F55-4152-5449-4E20-205630303031"
#define POSNET_CHAR_RX_UUID "53544F55-4152-5449-4E20-205630303031"
#define RBL_BLE_FRAMEWORK_VER 0x0200
//
// CBPeripheral+BTSExtensions.h
// BluetoothSerial Cordova Plugin
//
// (c) 2103-2015 Don Coleman
//
// 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 <objc/runtime.h>
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface CBPeripheral(com_megster_bluetoothserial_extension)
@property (nonatomic, retain) NSString *btsAdvertising;
@property (nonatomic, retain) NSNumber *btsAdvertisementRSSI;
-(void)bts_setAdvertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber*)rssi;
@end
//
// CBPeripheral+BTSExtensions.m
// BluetoothSerial Cordova Plugin
//
// (c) 2103-2015 Don Coleman
//
// 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 "CBPeripheral+BTSExtensions.h"
static char BTS_ADVERTISING_IDENTIFER;
static char BTS_ADVERTISEMENT_RSSI_IDENTIFER;
@implementation CBPeripheral(com_megster_bluetoothserial_extension)
// AdvertisementData and RSSI are from didDiscoverPeripheral.
// Save the manufacturerData so we can pass to Cordova in the peripheral
-(void)bts_setAdvertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)rssi{
if (advertisementData) {
id manufacturerData = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
if (manufacturerData) {
const uint8_t *bytes = [manufacturerData bytes];
long len = [manufacturerData length];
// skip manufacturer uuid
NSData *data = [NSData dataWithBytes:bytes+2 length:len-2];
[self setBtsAdvertising: [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
}
}
[self setBtsAdvertisementRSSI: rssi];
}
-(void)setBtsAdvertising:(NSString *)newAdvertisingValue{
objc_setAssociatedObject(self, &BTS_ADVERTISING_IDENTIFER, newAdvertisingValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString*)btsAdvertising{
return objc_getAssociatedObject(self, &BTS_ADVERTISING_IDENTIFER);
}
-(void)setBtsAdvertisementRSSI:(NSNumber *)newAdvertisementRSSIValue {
objc_setAssociatedObject(self, &BTS_ADVERTISEMENT_RSSI_IDENTIFER, newAdvertisementRSSIValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString*)btsAdvertisementRSSI{
return objc_getAssociatedObject(self, &BTS_ADVERTISEMENT_RSSI_IDENTIFER);
}
@end
/*
File: EADSessionController.h
Abstract: n/a
Version: 1.1
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2010 Apple Inc. All Rights Reserved.
*/
#import <Foundation/Foundation.h>
#import <ExternalAccessory/ExternalAccessory.h>
extern NSString *EADSessionDataReceivedNotification;
// NOTE: EADSessionController is not threadsafe, calling methods from different threads will lead to unpredictable results
@interface EADSessionController : NSObject <EAAccessoryDelegate, NSStreamDelegate> {
EAAccessory *_accessory;
EASession *_session;
NSString *_protocolString;
NSMutableData *_writeData;
NSMutableData *_readData;
}
+ (EADSessionController *)sharedController;
- (void)setupControllerForAccessory:(EAAccessory *)accessory withProtocolString:(NSString *)protocolString;
- (BOOL)openSession;
- (void)closeSession;
- (void)writeData:(NSData *)data;
- (NSUInteger)readBytesAvailable;
- (NSData *)readData:(NSUInteger)bytesToRead;
@property (nonatomic, readonly) EAAccessory *accessory;
@property (nonatomic, readonly) NSString *protocolString;
@end
/*
File: EADSessionController.m
Abstract: n/a
Version: 1.1
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2010 Apple Inc. All Rights Reserved.
*/
#import "EADSessionController.h"
NSString *EADSessionDataReceivedNotification = @"EADSessionDataReceivedNotification";
@implementation EADSessionController
@synthesize accessory = _accessory;
@synthesize protocolString = _protocolString;
#pragma mark Internal
// low level write method - write data to the accessory while there is space available and data to write
- (void)_writeData {
if(_session == nil)
{
NSLog(@"No session!");
}
if(![[_session outputStream] hasSpaceAvailable])
{
NSLog(@"Has no space");
}
while (([[_session outputStream] hasSpaceAvailable]) && ([_writeData length] > 0))
{
NSInteger bytesWritten = [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]];
if (bytesWritten == -1)
{
NSLog( @"write error");
break;
}
else if (bytesWritten > 0)
{
[_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
NSLog(@"Written!%d",(int)bytesWritten);
}
}
}
// low level read method - read data while there is data and space available in the input buffer
- (void)_readData {
#define EAD_INPUT_BUFFER_SIZE 128
uint8_t buf[EAD_INPUT_BUFFER_SIZE];
while ([[_session inputStream] hasBytesAvailable])
{
NSInteger bytesRead = [[_session inputStream] read:buf maxLength:EAD_INPUT_BUFFER_SIZE];
if (_readData == nil) {
_readData = [[NSMutableData alloc] init];
}
[_readData appendBytes:(void *)buf length:bytesRead];
//NSLog(@"read %d bytes from input stream", bytesRead);
}
[[NSNotificationCenter defaultCenter] postNotificationName:EADSessionDataReceivedNotification object:self userInfo:nil];
}
#pragma mark Public Methods
+ (EADSessionController *)sharedController
{
static EADSessionController *sessionController = nil;
if (sessionController == nil) {
sessionController = [[EADSessionController alloc] init];
}
return sessionController;
}
- (void)dealloc
{
[self closeSession];
[self setupControllerForAccessory:nil withProtocolString:nil];
}
// initialize the accessory with the protocolString
- (void)setupControllerForAccessory:(EAAccessory *)accessory withProtocolString:(NSString *)protocolString
{
_protocolString = [protocolString copy];
_accessory = accessory;
}
// open a session with the accessory and set up the input and output stream on the default run loop
- (BOOL)openSession
{
[_accessory setDelegate:self];
_session = [[EASession alloc] initWithAccessory:_accessory forProtocol:_protocolString];
if (_session)
{
[[_session inputStream] setDelegate:self];
[[_session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session inputStream] open];
[[_session outputStream] setDelegate:self];
[[_session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session outputStream] open];
}
else
{
NSLog(@"creating session failed");
}
return (_session != nil);
}
// close the session with the accessory.
- (void)closeSession
{
[[_session inputStream] close];
[[_session inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session inputStream] setDelegate:nil];
[[_session outputStream] close];
[[_session outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[_session outputStream] setDelegate:nil];
_session = nil;
_writeData = nil;
_readData = nil;
}
// high level write data method
- (void)writeData:(NSData *)data
{
if (_writeData == nil) {
_writeData = [[NSMutableData alloc] init];
}
[_writeData appendData:data];
[self _writeData];
}
// high level read method
- (NSData *)readData:(NSUInteger)bytesToRead
{
NSData *data = nil;
if ([_readData length] >= bytesToRead) {
NSRange range = NSMakeRange(0, bytesToRead);
data = [_readData subdataWithRange:range];
[_readData replaceBytesInRange:range withBytes:NULL length:0];
}
return data;
}
// get number of bytes read into local buffer
- (NSUInteger)readBytesAvailable
{
return [_readData length];
}
#pragma mark EAAccessoryDelegate
- (void)accessoryDidDisconnect:(EAAccessory *)accessory
{
// do something ...
}
#pragma mark NSStreamDelegateEventExtensions
// asynchronous NSStream handleEvent method
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
[self _readData];
break;
case NSStreamEventHasSpaceAvailable:
[self _writeData];
break;
case NSStreamEventErrorOccurred:
break;
case NSStreamEventEndEncountered:
break;
default:
break;
}
}
@end
/*
Created by Nuttawut Malee on 10.11.18.
Copyright © 2016 Nuttawut Malee. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#import "BLE.h"
#import "EADSessionController.h"
#import <ExternalAccessory/ExternalAccessory.h>
typedef void (^RCTBluetoothSerialPeripheralCallback) (CBPeripheral *_Nullable peripheral);
/*!
* RCTBluetoothSerial is an abstract base class to be used for module that connect,
* read and write data from active peripheral.
*/
@interface RCTBluetoothSerial : RCTEventEmitter <RCTBridgeModule, BLEDelegate, EAAccessoryDelegate>
/*!
* BLE central manager, for scanning and connection events.
*/
@property (strong, nonatomic, readonly) BLE *ble;
/*!
* Indicates if there are at least one listeners from RCTEventEmitter.
*/
@property (assign, nonatomic) BOOL doesHaveListeners;
/*!
* Dictionary of buffer from each active peripherals read value.
*/
@property (strong, nonatomic) NSMutableDictionary *buffers;
/*!
* Dictionary of certain delimiter to indicate the end of sliced buffer.
*/
@property (strong, nonatomic) NSMutableDictionary *delimiters;
/*!
* Resolvers an rejectors for connection related function.
*/
@property (strong, nonatomic) NSMutableDictionary *connectionPromises;
/**
* @method bluetoothPowerStateTimer
*
* @param timer
*
* @discussion Indicates central manager power state.
*
*/
- (void)bluetoothPowerStateTimer:(NSTimer *)timer;
@property (strong, nonatomic) NSMutableArray *accessoryList;
@property(nonatomic,retain)EADSessionController *glucoseEADSessionController;
@end
/*
Created by Nuttawut Malee on 10.11.18.
Copyright © 2016 Nuttawut Malee. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#import "RCTBluetoothSerial.h"
@implementation RCTBluetoothSerial
RCT_EXPORT_MODULE();
@synthesize bridge = _bridge;
/*----------------------------------------------------*/
#pragma mark - Lifecycle -
/*----------------------------------------------------*/
- (instancetype)init
{
self = [super init];
if (self) {
_buffers = [NSMutableDictionary dictionary];
_delimiters = [NSMutableDictionary dictionary];
_connectionPromises = [NSMutableDictionary dictionary];
_doesHaveListeners = FALSE;
_ble = [[BLE alloc] init];
[_ble setDelegate:self];
}
return self;
}
- (dispatch_queue_t)methodQueue
{
// run all module methods in main thread
// if we don't no timer callbacks got called
return dispatch_get_main_queue();
}
+ (BOOL)requiresMainQueueSetup
{
return NO;
}
/*----------------------------------------------------*/
#pragma mark - React Native Methods Available in Javascript -
/*----------------------------------------------------*/
- (NSDictionary *)constantsToExport
{
return @{@"DEFAULT_SERVICES":[self.ble getDefaultServices]};
}
RCT_EXPORT_METHOD(requestEnable:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically requesting enable central manager
NSString *message = @"Require enable bluetooth service; Apple does not support this function";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(enable:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically enabling central manager
NSString *message = @"Enable bluetooth service; Apple does not support this function";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(disable:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically disabling central manager
NSString *message = @"Disable bluetooth service; Apple does not support this function";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(isEnabled:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Short delay so CBCentralManger can spin up bluetooth
[NSTimer scheduledTimerWithTimeInterval:(float)0.2
target:self
selector:@selector(bluetoothPowerStateTimer:)
userInfo:resolve
repeats:NO];
}
- (void)_accessoryDidConnect:(NSNotification *)notification
{
EAAccessory *connectedAccessory = [[notification userInfo] objectForKey:EAAccessoryKey];
// NSLog(@"Connected Accessory = %@", connectedAccessory);
[_accessoryList addObject:connectedAccessory];
NSLog(@"ConnectedAccessories = %@", _accessoryList);
}
- (void)_accessoryDidDisconnect:(NSNotification *)notification
{
EAAccessory *disconnectedAccessory = [[notification userInfo] objectForKey:EAAccessoryKey];
int disconnectedAccessoryIndex = 0;
for(EAAccessory *accessory in _accessoryList) {
if ([disconnectedAccessory connectionID] == [accessory connectionID]) {
break;
}
disconnectedAccessoryIndex++;
}
if (disconnectedAccessoryIndex < [_accessoryList count]) {
[_accessoryList removeObjectAtIndex:disconnectedAccessoryIndex];
} else {
NSLog(@"could not find disconnected accessory in accessory list");
}
NSLog(@"ConnectedAccessories = %@", _accessoryList);
}
// Data was received from the accessory, real apps should do something with this data but currently:
- (void)_sessionDataReceived:(NSNotification *)notification
{
// NSLog(@"_sessionDataReceived %@", notification);
EADSessionController *sessionController = (EADSessionController *)[notification object];
NSInteger bytesAvailable = 0;
NSString *uuid = [NSString stringWithFormat: @"%ld", (long)sessionController.accessory.connectionID];
NSLog(@"Received uuid %@", uuid);
while ((bytesAvailable = [sessionController readBytesAvailable]) > 0) {
NSData *d = [sessionController readData:bytesAvailable];
NSString *s = [[NSString alloc] initWithData:d encoding:NSISOLatin1StringEncoding];
if (s) {
// NSLog(@"Received string %@", s);
// Append buffers
if ([[self.buffers allKeys] containsObject:uuid]) {
NSMutableString *buffer = [self.buffers valueForKey:uuid];
[buffer appendString:s];
[self.buffers setValue:buffer forKey:uuid];
} else {
NSMutableString *buffer = [[NSMutableString alloc] init];
[buffer appendString:s];
[self.buffers setValue:buffer forKey:uuid];
}
NSMutableString *delimiter = [[NSMutableString alloc] initWithString:@""];
if ([[self.delimiters allKeys] containsObject:uuid]) {
[delimiter setString:[self.delimiters valueForKey:uuid]];
}
NSLog(@"Read until delimiter : %@", delimiter);
NSString *message = [self readUntil:uuid delimiter:delimiter];
if ([message length] > 0) {
if (self.doesHaveListeners) {
[self sendEventWithName:@"read" body:@{@"id":uuid, @"data":message}];
[self sendEventWithName:@"data" body:@{@"id":uuid, @"data":message}];
}
}
} else {
[self onError:@"Error converting received data into a string"];
}
}
}
RCT_EXPORT_METHOD(list:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"List peripherals");
[[NSNotificationCenter defaultCenter] removeObserver:self name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:EAAccessoryDidDisconnectNotification object:nil];
_accessoryList = nil;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_accessoryDidConnect:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_accessoryDidDisconnect:) name:EAAccessoryDidDisconnectNotification object:nil];
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_sessionDataReceived:) name:EADSessionDataReceivedNotification object:nil];
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
_accessoryList = [[NSMutableArray alloc] initWithArray:[[EAAccessoryManager sharedAccessoryManager] connectedAccessories]];
// NSLog(@"ConnectedAccessories = %@", _accessoryList);
NSMutableArray *devices = [[NSMutableArray alloc]init];
for(int i=0;i<_accessoryList.count;i++)
{
/*if([[[_accessoryList objectAtIndex:i] name] isEqualToString:@"TD_MFI_BT"])
{
self.glucoseEADSessionController = [EADSessionController sharedController];
[self.glucoseEADSessionController setupControllerForAccessory:[_accessoryList objectAtIndex:i] withProtocolString:@"com.taidoc.taidocbus.ec"];
[self.glucoseEADSessionController openSession];
}*/
NSDictionary *device = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSString stringWithFormat: @"%ld", (long)[[_accessoryList objectAtIndex:i] connectionID]], @"id",
@"", @"rssi",
[[_accessoryList objectAtIndex:i] name], @"uuid",
// [[[_accessoryList objectAtIndex:i] protocolStrings] objectAtIndex:0], @"name", nil];
@"TAIDOC TD2202", @"name", nil];
[devices addObject:device];
}
resolve(devices);
// Byte byte[] = {0x51, 0x48, 0x1b, 0x01, 0x01, 0x01, 0xa3, 0x5a};
// NSData *data = [[NSData alloc] initWithBytes:byte length:24];
// [[EADSessionController sharedController] writeData:data];
/*[self.ble scanForPeripheralsByInterval:(float)10.0 completion:^(NSMutableArray *peripherals) {
NSMutableArray *result = [self getPeripheralList:peripherals];
resolve(result);
}];*/
}
RCT_EXPORT_METHOD(listUnpaired:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically enabling central manager
NSString *message = @"List unpaired peripherals; Apple does not support this function";
[self onError:message];
resolve([NSMutableArray new]);
}
RCT_EXPORT_METHOD(cancelDiscovery:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"Cancel discovery called");
[self.ble stopScanForPeripherals];
resolve((id)kCFBooleanTrue);
}
RCT_EXPORT_METHOD(pairDevice:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically pairing.
NSString *message = @"Pair to peripheral (UUID : %@); Apple does not support this function";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(unpairDevice:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically unpairing.
NSString *message = @"Unpair to peripheral (UUID : %@); Apple does not support this function";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(connect:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"Connect to peripheral");
NSUInteger connectionID = (NSUInteger)uuid.longLongValue;
NSDictionary *device = nil;
for(int i=0;i<_accessoryList.count;i++)
{
if([[_accessoryList objectAtIndex:i] connectionID] == connectionID)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_sessionDataReceived:) name:EADSessionDataReceivedNotification object:nil];
self.glucoseEADSessionController = [EADSessionController sharedController];
[self.glucoseEADSessionController setupControllerForAccessory:[_accessoryList objectAtIndex:i] withProtocolString:[[[_accessoryList objectAtIndex:i] protocolStrings] objectAtIndex:0]];
[self.glucoseEADSessionController openSession];
device = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSString stringWithFormat: @"%ld", (long)[[_accessoryList objectAtIndex:i] connectionID]], @"id",
@"", @"rssi",
[[_accessoryList objectAtIndex:i] name], @"uuid",
[[[_accessoryList objectAtIndex:i] protocolStrings] objectAtIndex:0], @"name", nil];
// [self.buffers ]
NSLog(@"Connected Accessory = %@", device);
}
}
if (device != nil) {
resolve(device);
} else {
NSString *message = [NSString stringWithFormat:@"Could not find peripheral %@.", uuid];
NSError *err = [NSError errorWithDomain:@"wrong_uuid" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"wrong_uuid", message, err);
}
/*
// Disconnect from selected active peripheral
NSMutableDictionary *dict = [self.ble.activePeripherals objectForKey:uuid];
if (dict) {
CBPeripheral *peripheral = [dict objectForKey:@"peripheral"];
if (peripheral) {
if (peripheral.state == CBPeripheralStateConnected) {
[self.ble disconnectFromPeripheral:peripheral];
}
}
}
NSMutableDictionary *promises = [NSMutableDictionary dictionary];
[promises setObject:resolve forKey:@"resolver"];
[promises setObject:reject forKey:@"rejector"];
[self.connectionPromises setObject:promises forKey:uuid];
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(findBLEPeripheralByUUID:completion:)
object:nil];
[self findBLEPeripheralByUUID:uuid completion:^(CBPeripheral *peripheral) {
if (peripheral) {
NSLog(@"Connecting to device (UUID : %@)", peripheral.identifier.UUIDString);
if (![[self.delimiters allKeys] containsObject:peripheral.identifier.UUIDString]) {
[self.delimiters setValue:[[NSMutableString alloc] initWithString:@""] forKey:peripheral.identifier.UUIDString];
}
if (![[self.buffers allKeys] containsObject:peripheral.identifier.UUIDString]) {
[self.buffers setValue:[[NSMutableString alloc] init] forKey:peripheral.identifier.UUIDString];
}
[self.ble connectToPeripheral:peripheral];
} else {
NSString *message = [NSString stringWithFormat:@"Could not find peripheral %@.", uuid];
NSError *err = [NSError errorWithDomain:@"wrong_uuid" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"wrong_uuid", message, err);
}
}];
*/
}
RCT_EXPORT_METHOD(disconnect:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"Disconnect from peripheral");
CBPeripheral *activePeripheral = [self.ble getActivePeripheral:uuid];
// Disconnect from selected active peripheral
if (activePeripheral) {
if (activePeripheral.state == CBPeripheralStateConnected) {
[self.ble disconnectFromPeripheral:activePeripheral];
}
}
resolve((id)kCFBooleanTrue);
}
RCT_EXPORT_METHOD(disconnectAll:(RCTPromiseResolveBlock)resolve rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"Disconnect from all peripherals");
NSMutableDictionary *peripherals = [[NSMutableDictionary alloc] initWithDictionary:self.ble.activePeripherals];
if ([peripherals count] > 0) {
NSArray *keys = [peripherals allKeys];
for (NSString *key in keys) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[peripherals objectForKey:key]];
if (dict) {
CBPeripheral *p = [dict objectForKey:@"peripheral"];
if (p) {
if (p.state == CBPeripheralStateConnected) {
[self.ble disconnectFromPeripheral:p];
}
}
}
}
}
resolve((id)kCFBooleanTrue);
}
RCT_EXPORT_METHOD(isConnected:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
if ([self.ble isConnected:uuid]) {
resolve((id)kCFBooleanTrue);
} else {
resolve((id)kCFBooleanFalse);
}
}
RCT_EXPORT_METHOD(withDelimiter:(NSString *)delimiter
uuid:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSMutableString *deviceUUID = nil;
if (![delimiter isKindOfClass:[NSNull class]] | (uuid == nil)) {
NSMutableString *newDelimiter = [[NSMutableString alloc] initWithString:delimiter];
NSLog(@"Set delimiter to %@ for UUID : %@", newDelimiter, uuid);
if ([uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
CBPeripheral *activePeripheral = [self.ble getActivePeripheral:uuid];
if (activePeripheral) {
[self.delimiters setValue:newDelimiter forKey:activePeripheral.identifier.UUIDString];
[deviceUUID setString:activePeripheral.identifier.UUIDString];
}
} else {
[self.delimiters setValue:newDelimiter forKey:uuid];
[deviceUUID setString:uuid];
}
}
resolve(deviceUUID);
}
RCT_EXPORT_METHOD(clear:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSMutableString *activeUUID = nil;
if ([uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
CBPeripheral *activePeripheral = [self.ble getActivePeripheral:uuid];
if (activePeripheral) {
[activeUUID setString:activePeripheral.identifier.UUIDString];
}
} else {
[activeUUID setString:uuid];
}
if ([[self.buffers allKeys] containsObject:activeUUID]) {
NSMutableString *buffer = [self.buffers valueForKey:activeUUID];
long end = [buffer length] - 1;
NSRange truncate = NSMakeRange(0, end);
[buffer deleteCharactersInRange:truncate];
[self.buffers setValue:buffer forKey:activeUUID];
}
resolve((id)kCFBooleanTrue);
}
RCT_EXPORT_METHOD(available:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSMutableString *activeUUID = nil;
if ([uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
CBPeripheral *activePeripheral = [self.ble getActivePeripheral:uuid];
if (activePeripheral) {
[activeUUID setString:activePeripheral.identifier.UUIDString];
}
} else {
[activeUUID setString:uuid];
}
NSNumber *bufferLength = 0;
if ([[self.buffers allKeys] containsObject:activeUUID]) {
NSMutableString *buffer = [self.buffers valueForKey:uuid];
bufferLength = [NSNumber numberWithInteger:[buffer length]];
}
resolve(bufferLength);
}
RCT_EXPORT_METHOD(setAdapterName:(NSString *)name
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
// Apple does not support programmatically adapter name setter.
NSString *message = @"Cannot set adapter name in iOS";
NSError *error = [NSError errorWithDomain:@"no_support" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
RCT_EXPORT_METHOD(setServices:(NSArray *)services
includeDefaultServices:(BOOL)includeDefault
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
if ([self.ble validateServices:services]) {
NSMutableArray *mutableServices = [[NSMutableArray alloc] initWithArray:services];
if (includeDefault) {
mutableServices = [[NSMutableArray alloc] initWithArray:[self.ble includeDefaultServices:mutableServices]];
}
[self.ble setBleServices:[self.ble servicesArrayToDictionary:mutableServices]];
NSArray *services = [self.ble servicesDictionaryToArray:self.ble.bleServices];
resolve(services);
} else {
NSString *message = @"Invalid array of service objects";
NSError *error = [NSError errorWithDomain:@"invalid_parameter" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
[self onError:message];
reject(@"", message, error);
}
}
RCT_EXPORT_METHOD(getServices:(RCTPromiseResolveBlock)resolve rejector:(RCTPromiseRejectBlock)reject)
{
NSArray *services = [self.ble servicesDictionaryToArray:self.ble.bleServices];
resolve(services);
}
RCT_EXPORT_METHOD(restoreServices:(RCTPromiseResolveBlock)resolve rejector:(RCTPromiseRejectBlock)reject)
{
[self.ble setBleServices:[self.ble servicesArrayToDictionary:[self.ble getDefaultServices]]];
NSArray *services = [self.ble servicesDictionaryToArray:self.ble.bleServices];
resolve(services);
}
RCT_EXPORT_METHOD(writeToDevice:(NSString *)message
uuid:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NSDataBase64DecodingIgnoreUnknownCharacters];
NSLog(@"Write to device : %@", data);
// Byte byte[] = {0x51, 0x48, 0x1b, 0x01, 0x01, 0x01, 0xa3, 0x5a};
// NSData *data = [[NSData alloc] initWithBytes:byte length:24];
if ([data length] > 0) {
[[EADSessionController sharedController] writeData:data];
} else {
NSLog(@"Data was null");
}
/*if ([data length] > 0) {
[self.ble write:uuid data:data];
} else {
NSLog(@"Data was null");
}*/
resolve((id)kCFBooleanTrue);
}
RCT_EXPORT_METHOD(readFromDevice:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSString *message = @"";
//NSMutableString *activeUUID = nil;
//[activeUUID setString:uuid];
// NSLog(@"Read from active device %@", uuid);
if ([[self.buffers allKeys] containsObject:uuid]) {
NSLog(@"Read from active device");
NSMutableString *buffer = [self.buffers valueForKey:uuid];
long end = [buffer length] - 1;
message = [buffer substringToIndex:end];
NSRange entireString = NSMakeRange(0, end);
[buffer deleteCharactersInRange:entireString];
[self.buffers setValue:buffer forKey:uuid];
}
resolve(message);
}
RCT_EXPORT_METHOD(readUntilDelimiter:(NSString *)delimiter
uuid:(NSString *)uuid
resolver:(RCTPromiseResolveBlock)resolve
rejector:(RCTPromiseRejectBlock)reject)
{
NSLog(@"Read until delimiter : %@", delimiter);
NSString *message = [self readUntil:uuid delimiter:delimiter];
resolve(message);
}
/*----------------------------------------------------*/
#pragma mark - Private Methods -
/*----------------------------------------------------*/
- (void)findBLEPeripheralByUUID: (NSString *)uuid
completion:(RCTBluetoothSerialPeripheralCallback)callback
{
NSLog(@"Scanning for BLE Peripherals: %@", uuid);
// Scan for peripherals.
// If the uuid is null or blank, scan and
// connect to the first available device.
[self.ble scanForPeripheralsByInterval:(float)3.0 completion:^(NSMutableArray *peripherals) {
CBPeripheral *peripheral = nil;
if ([peripherals count] < 1) {
[self onError:@"Did not find any BLE peripherals"];
} else {
if (([uuid length] <= 0) | [uuid isEqualToString:@""] | [uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
// First device found
peripheral = [peripherals objectAtIndex:0];
} else {
// Device by UUID
for (CBPeripheral *p in self.ble.peripherals) {
if ([uuid isEqualToString:p.identifier.UUIDString]) {
peripheral = p;
break;
}
}
}
}
if (callback) {
callback(peripheral);
}
}];
}
- (NSMutableArray *)getPeripheralList:(NSMutableArray *)peripherals
{
NSMutableArray *result = [NSMutableArray array];
if ([peripherals count] > 0) {
for (int i = 0; i < peripherals.count; i++) {
CBPeripheral *peripheral = [self.ble.peripherals objectAtIndex:i];
NSMutableDictionary *dict = [self.ble peripheralToDictionary:peripheral];
[result addObject:dict];
}
}
return result;
}
- (NSString *)readUntil:(NSString *)uuid delimiter:(NSString *)delimiter
{
NSMutableString *activeUUID = nil;
if ([uuid isKindOfClass:[NSNull class]] | (uuid == nil)) {
CBPeripheral *activePeripheral = [self.ble getActivePeripheral:uuid];
if (activePeripheral) {
[activeUUID setString:activePeripheral.identifier.UUIDString];
}
} else {
[activeUUID setString:uuid];
}
NSString *message = @"";
if ([[self.buffers allKeys] containsObject:activeUUID]) {
NSMutableString *buffer = [self.buffers valueForKey:activeUUID];
NSRange range = [buffer rangeOfString:delimiter];
if (range.location != NSNotFound) {
long end = range.location + range.length;
message = [buffer substringToIndex:end];
NSRange truncate = NSMakeRange(0, end);
[buffer deleteCharactersInRange:truncate];
[self.buffers setValue:buffer forKey:activeUUID];
}
}
return message;
}
- (void)onError:(NSString *)message
{
NSLog(@"%@", message);
if (self.doesHaveListeners) {
[self sendEventWithName:@"error" body:@{@"message":message}];
}
}
/*----------------------------------------------------*/
#pragma mark - Timers -
/*----------------------------------------------------*/
- (void)bluetoothPowerStateTimer:(NSTimer *)timer
{
RCTPromiseResolveBlock resolve = [timer userInfo];
if (self.ble.isCentralReady) {
resolve((id)kCFBooleanTrue);
} else {
resolve((id)kCFBooleanFalse);
}
}
/*----------------------------------------------------*/
#pragma mark - BLE Delegate -
/*----------------------------------------------------*/
- (void)didPowerOn
{
if (self.doesHaveListeners) {
[self sendEventWithName:@"bluetoothEnabled" body:nil];
}
}
- (void)didPowerOff
{
if (self.doesHaveListeners) {
[self sendEventWithName:@"bluetoothDisabled" body:nil];
}
}
- (void)didConnect:(CBPeripheral *)peripheral
{
NSMutableDictionary *device = [self.ble peripheralToDictionary:peripheral];
NSString *message = [NSString stringWithFormat:@"Connected to BLE peripheral (UUID : %@)", peripheral.identifier.UUIDString];
NSLog(@"%@", message);
if (self.doesHaveListeners) {
[self sendEventWithName:@"connectionSuccess" body:@{@"message":message, @"device":device}];
}
if ([[self.connectionPromises allKeys] containsObject:peripheral.identifier.UUIDString]) {
NSMutableDictionary *dict = [self.connectionPromises objectForKey:peripheral.identifier.UUIDString];
RCTPromiseResolveBlock resolver = [dict objectForKey:@"resolver"];
if (resolver) {
resolver(device);
}
}
}
- (void)didFailToConnect:(CBPeripheral *)peripheral
{
NSMutableDictionary *device = [self.ble peripheralToDictionary:peripheral];
NSString *message = [NSString stringWithFormat:@"Unable to connect to BLE peripheral (UUID : %@)", peripheral.identifier.UUIDString];
NSLog(@"%@", message);
if (self.doesHaveListeners) {
[self sendEventWithName:@"connectionFailed" body:@{@"message":message, @"device":device}];
}
if ([[self.connectionPromises allKeys] containsObject:peripheral.identifier.UUIDString]) {
NSMutableDictionary *dict = [self.connectionPromises objectForKey:peripheral.identifier.UUIDString];
RCTPromiseRejectBlock reject = [dict objectForKey:@"rejector"];
if (reject) {
NSError *err = [NSError errorWithDomain:@"fail_to_connect" code:500 userInfo:@{NSLocalizedDescriptionKey:message}];
reject(@"wrong_uuid", message, err);
}
}
}
- (void)didConnectionLost:(CBPeripheral *)peripheral
{
NSMutableDictionary *device = [self.ble peripheralToDictionary:peripheral];
NSString *message = [NSString stringWithFormat:@"BLE peripheral (UUID : %@) connection lost", peripheral.identifier.UUIDString];
NSLog(@"%@", message);
if (self.doesHaveListeners) {
[self sendEventWithName:@"connectionLost" body:@{@"message":message, @"device":device}];
}
[self.connectionPromises removeObjectForKey:peripheral.identifier.UUIDString];
}
- (void)didReceiveData:(NSString *)uuid data:(unsigned char *)data length:(NSInteger)length
{
NSLog(@"Received data from peripheral UUID : %@", uuid);
NSData *d = [NSData dataWithBytes:data length:length];
NSString *s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
if (s) {
NSLog(@"Received %@", s);
// Append buffers
if ([[self.buffers allKeys] containsObject:uuid]) {
NSMutableString *buffer = [self.buffers valueForKey:uuid];
[buffer appendString:s];
[self.buffers setValue:buffer forKey:uuid];
}
NSMutableString *delimiter = [[NSMutableString alloc] initWithString:@""];
if ([[self.delimiters allKeys] containsObject:uuid]) {
[delimiter setString:[self.delimiters valueForKey:uuid]];
}
NSLog(@"Read until delimiter : %@", delimiter);
NSString *message = [self readUntil:uuid delimiter:delimiter];
if ([message length] > 0) {
if (self.doesHaveListeners) {
[self sendEventWithName:@"read" body:@{@"id":uuid, @"data":message}];
[self sendEventWithName:@"data" body:@{@"id":uuid, @"data":message}];
}
}
} else {
[self onError:@"Error converting received data into a string"];
}
}
- (void)didError:(NSError *)error
{
NSString *message = [error localizedDescription];
[self onError:message];
}
/*----------------------------------------------------*/
#pragma mark - RCT Event Emitter -
/*----------------------------------------------------*/
- (NSArray<NSString *> *)supportedEvents
{
return @[@"bluetoothEnabled", @"bluetoothDisabled", @"connectionSuccess", @"connectionFailed", @"connectionLost", @"read", @"data", @"error"];
}
- (void)startObserving
{
self.doesHaveListeners = TRUE;
}
- (void)stopObserving
{
self.doesHaveListeners = FALSE;
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment