Last active
August 29, 2015 14:00
-
-
Save jsorge/11390537 to your computer and use it in GitHub Desktop.
CoreBluetooth Helpers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// JMSBTCentral.h | |
// CP130_HW2_Bluetooth | |
// | |
// Created by Jared Sorge on 4/20/14. | |
// Copyright (c) 2014 jsorge. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol JMSBTCentralDelegate; | |
@interface JMSBTCentral : NSObject | |
@property (weak, nonatomic)id<JMSBTCentralDelegate>delegate; | |
@property (readonly, nonatomic)BOOL scanning; | |
- (instancetype)initWithDelegate:(id<JMSBTCentralDelegate>)delegate serviceID:(NSString *)serviceID characteristicID:(NSString *)characteristicID; | |
- (void)startUpdating; | |
- (void)stopUpdating; | |
@end | |
@protocol JMSBTCentralDelegate <NSObject> | |
- (void)jmsCentralDidUpdateDataOutput:(JMSBTCentral *)central withString:(NSString *)outputString; | |
- (void)jmsCentralDidConnectToPeripheral:(JMSBTCentral *)central; | |
- (void)jmsCentralDidDisconnectPeripheral:(JMSBTCentral *)central; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// JMSBTCentral.m | |
// CP130_HW2_Bluetooth | |
// | |
// Created by Jared Sorge on 4/20/14. | |
// Copyright (c) 2014 jsorge. All rights reserved. | |
// | |
#import "JMSBTCentral.h" | |
#import <CoreBluetooth/CoreBluetooth.h> | |
@interface JMSBTCentral ()<CBCentralManagerDelegate, CBPeripheralDelegate> | |
@property (readwrite, nonatomic)NSMutableData *dataOutput; | |
@property (readwrite, nonatomic)BOOL scanning; | |
@property (strong, nonatomic)CBUUID *serviceUUID; | |
@property (strong, nonatomic)CBUUID *characteristicUUID; | |
@property (strong, nonatomic)CBCentralManager *manager; | |
@property (strong, nonatomic)CBPeripheral *peripheral; | |
@end | |
@implementation JMSBTCentral | |
#pragma mark - API | |
- (instancetype)initWithDelegate:(id<JMSBTCentralDelegate>)delegate serviceID:(NSString *)serviceID characteristicID:(NSString *)characteristicID | |
{ | |
self = [super init]; | |
if (self) { | |
self.serviceUUID = [CBUUID UUIDWithString:serviceID]; | |
self.characteristicUUID = [CBUUID UUIDWithString:characteristicID]; | |
self.delegate = delegate; | |
[self startUpdating]; | |
} | |
return self; | |
} | |
- (void)startUpdating | |
{ | |
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; | |
} | |
- (void)stopUpdating | |
{ | |
[self.manager stopScan]; | |
if (self.peripheral) { | |
[self.manager cancelPeripheralConnection:self.peripheral]; | |
} | |
self.scanning = NO; | |
} | |
#pragma mark - Properties | |
- (NSMutableData *)dataOutput | |
{ | |
if (!_dataOutput) { | |
_dataOutput = [NSMutableData data]; | |
} | |
return _dataOutput; | |
} | |
#pragma mark - CBCentralManagerDelegate | |
- (void)centralManagerDidUpdateState:(CBCentralManager *)central | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (central.state == CBCentralManagerStatePoweredOn) { | |
[self startCentralScan]; | |
self.scanning = YES; | |
} | |
} | |
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (peripheral != self.peripheral) { | |
self.peripheral = peripheral; | |
[self.manager connectPeripheral:peripheral options:nil]; | |
} | |
} | |
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
[self cleanup]; | |
} | |
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
[self.manager stopScan]; | |
self.dataOutput = nil; | |
peripheral.delegate = self; | |
[peripheral discoverServices:@[self.serviceUUID]]; | |
[self.delegate jmsCentralDidConnectToPeripheral:self]; | |
} | |
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
self.peripheral = nil; | |
[self.delegate jmsCentralDidDisconnectPeripheral:self]; | |
[self startCentralScan]; | |
} | |
#pragma mark - CBPeripheralDelegate | |
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (error) { | |
NSLog(@"Error: %@", error); | |
[self cleanup]; | |
return; | |
} | |
for (CBService *service in peripheral.services) { | |
NSLog(@"Found service %@", service.UUID); | |
[peripheral discoverCharacteristics:@[self.characteristicUUID] | |
forService:service]; | |
} | |
} | |
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (error) { | |
NSLog(@"Erro: %@", error); | |
[self cleanup]; | |
return; | |
} | |
for (CBCharacteristic *characteristic in service.characteristics) { | |
if ([characteristic.UUID isEqual:self.characteristicUUID]) { | |
[peripheral setNotifyValue:YES forCharacteristic:characteristic]; | |
NSLog(@"discovered characteristic %@", characteristic.UUID); | |
} | |
} | |
} | |
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (error) { | |
NSLog(@"Error: %@", error); | |
return; | |
} | |
NSString *receivedString = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; | |
if ([receivedString isEqualToString:@"EOM"]) { | |
[peripheral setNotifyValue:NO forCharacteristic:characteristic]; | |
[self.manager cancelPeripheralConnection:peripheral]; | |
} else { | |
[self.delegate jmsCentralDidUpdateDataOutput:self withString:receivedString]; | |
} | |
} | |
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
if (![characteristic.UUID isEqual:self.characteristicUUID]) { | |
return; | |
} | |
if (!characteristic.isNotifying) { | |
[self.manager cancelPeripheralConnection:peripheral]; | |
} | |
} | |
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices | |
{ | |
NSLog(@"%s", __PRETTY_FUNCTION__); | |
} | |
#pragma mark - Private | |
- (void)cleanup | |
{ | |
if (self.peripheral.services != nil) { | |
for (CBService *service in self.peripheral.services) { | |
if (service.peripheral != nil) { | |
for (CBCharacteristic *characteristic in service.characteristics) { | |
if (characteristic.isNotifying) { | |
[self.peripheral setNotifyValue:NO forCharacteristic:characteristic]; | |
} | |
} | |
} | |
} | |
} | |
} | |
- (void)startCentralScan | |
{ | |
[self.manager scanForPeripheralsWithServices:@[self.serviceUUID] | |
options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// JMSBTPeripheral.h | |
// ImHere | |
// | |
// Created by Jared Sorge on 4/13/14. | |
// Copyright (c) 2014 jsorge. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol JMSBTPeripheralDelegate; | |
@interface JMSBTPeripheral : NSObject | |
@property (readonly, nonatomic)BOOL broadcasting; | |
@property (weak, nonatomic)id<JMSBTPeripheralDelegate>delegate; | |
@property (strong, nonatomic)NSData *dataToSend; | |
- (instancetype)initWithDelegate:(id<JMSBTPeripheralDelegate>)delegate serviceID:(NSString *)serviceID characteristicID:(NSString *)characteristicID; | |
- (void)broadcastData:(NSString *)data; | |
- (void)startBroadcasting; | |
- (void)stopBroadcasting; | |
@end | |
@protocol JMSBTPeripheralDelegate <NSObject> | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// JMSBTPeripheral.m | |
// ImHere | |
// | |
// Created by Jared Sorge on 4/13/14. | |
// Copyright (c) 2014 jsorge. All rights reserved. | |
// | |
#import "JMSBTPeripheral.h" | |
#import <CoreBluetooth/CoreBluetooth.h> | |
@interface JMSBTPeripheral () <CBPeripheralManagerDelegate> | |
@property (readwrite, nonatomic)BOOL broadcasting; | |
@property (strong, nonatomic)CBUUID *serviceUUID; | |
@property (strong, nonatomic)CBUUID *characteristicUUID; | |
@property (strong, nonatomic)CBPeripheralManager *peripheralManager; | |
@property (strong, nonatomic)CBMutableCharacteristic *transferCharacteristic; | |
@property (strong, nonatomic)CBMutableService *service; | |
@property (nonatomic)NSInteger sendDataIndex; | |
@end | |
@implementation JMSBTPeripheral | |
#pragma mark - API | |
- (instancetype)initWithDelegate:(id<JMSBTPeripheralDelegate>)delegate serviceID:(NSString *)serviceID characteristicID:(NSString *)characteristicID | |
{ | |
self = [super init]; | |
if (self) { | |
self.delegate = delegate; | |
self.serviceUUID = [CBUUID UUIDWithString:serviceID]; | |
self.characteristicUUID = [CBUUID UUIDWithString:characteristicID]; | |
} | |
return self; | |
} | |
- (void)broadcastData:(NSString *)data | |
{ | |
if (self.broadcasting) { | |
self.dataToSend = [data dataUsingEncoding:NSStringEncodingConversionExternalRepresentation]; | |
self.sendDataIndex = 0; | |
[self sendData]; | |
} | |
} | |
- (void)startBroadcasting | |
{ | |
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; | |
[self.peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey: @[self.serviceUUID]}]; | |
self.broadcasting = YES; | |
NSLog(@"Started broadcasting"); | |
} | |
- (void)stopBroadcasting | |
{ | |
[self.peripheralManager stopAdvertising]; | |
[self.peripheralManager removeAllServices]; | |
self.peripheralManager = nil; | |
self.broadcasting = NO; | |
} | |
#pragma mark - Properties | |
- (CBPeripheralManager *)peripheralManager | |
{ | |
if (!_peripheralManager) { | |
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; | |
} | |
return _peripheralManager; | |
} | |
#pragma mark - CBPeripheralManagerDelegate | |
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral | |
{ | |
if (peripheral.state != CBPeripheralManagerStatePoweredOn) { | |
return; | |
} | |
self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:self.characteristicUUID | |
properties:CBCharacteristicPropertyNotify | |
value:nil | |
permissions:CBAttributePermissionsReadable]; | |
CBMutableService *transferService = [[CBMutableService alloc] initWithType:self.serviceUUID | |
primary:YES]; | |
transferService.characteristics = @[self.transferCharacteristic]; | |
[self.peripheralManager addService:transferService]; | |
} | |
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic | |
{ | |
[self sendData]; | |
} | |
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral | |
{ | |
[self sendData]; | |
} | |
#pragma mark - Private | |
- (void)sendData | |
{ | |
static BOOL sendingEndOfMessage = NO; | |
if (sendingEndOfMessage) { | |
BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] | |
forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; | |
if (didSend) { | |
sendingEndOfMessage = NO; | |
} | |
return; | |
} | |
if (self.sendDataIndex >= self.dataToSend.length) { | |
return; | |
} | |
BOOL didSend = YES; | |
while (didSend) { | |
NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex; | |
amountToSend = amountToSend > 20 ? 20 : amountToSend; | |
NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend]; | |
didSend = [self.peripheralManager updateValue:chunk | |
forCharacteristic:self.transferCharacteristic | |
onSubscribedCentrals:nil]; | |
if (!didSend) { | |
return; | |
} | |
NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding]; | |
NSLog(@"Sent: %@", stringFromData); | |
self.sendDataIndex += amountToSend; | |
if (self.sendDataIndex >= self.dataToSend.length || self.sendDataIndex == self.dataToSend.length) { | |
sendingEndOfMessage = YES; | |
BOOL endOfMessageSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] | |
forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil]; | |
if (endOfMessageSent) { | |
sendingEndOfMessage = NO; | |
NSLog(@"Sent: EOM"); | |
} | |
return; | |
} | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment