Write data to multiple BLE(bluetooth) devices - ios

Please check the following scenario:
ConnectDevices Class:
This method is for connect to BLE device. I am calling this method from ViewController to connect to the BLE device.
-(void)connectToDevice:(CBPeripheral *)peripheral{
[[AppDelegate app] cbCentral].delegate = self;
[[[AppDelegate app] cbCentral] connectPeripheral:peripheral options:nil];
}
This method is for discover the services for connected BLE device. I am calling method from NSOperation subclass
-(void)calldiscoverServicesForPeripheral:(CBPeripheral *)peripheral{
[peripheral setDelegate:self];
[peripheral discoverServices:#[[Utility SERVICE_UUID]]];
}
This method is for write the data to BLE device. I am calling from NSOperation class for every second.
-(void)writeDataToPeripheral:(CBPeripheral *)peripheral Data:(NSData *)data{
if (self.uartCharacteristic) {
[peripheral writeValue:data forCharacteristic:self.uartCharacteristic type:CBCharacteristicWriteWithoutResponse];
}
}
CBCentralManager delegate methods for getting state of the device
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
printf("Status of CoreBluetooth central manager changed %d \r\n",central.state);
// Determine the state of the peripheral
if ([central state] == CBCentralManagerStatePoweredOff) {
NSLog(#"CoreBluetooth BLE hardware is powered off");
}
else if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
}
else if ([central state] == CBCentralManagerStateUnauthorized) {
NSLog(#"CoreBluetooth BLE state is unauthorized");
}
else if ([central state] == CBCentralManagerStateUnknown) {
NSLog(#"CoreBluetooth BLE state is unknown");
}
else if ([central state] == CBCentralManagerStateUnsupported) {
NSLog(#"CoreBluetooth BLE hardware is unsupported on this platform");
}
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[delegate getConnectedPeripheral:peripheral];
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
[delegate getConnectedPeripheral:peripheral];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(#"didFailToConnectPeripheral %#",peripheral);
}
pragma mark - CBPeripheralDelegate
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
// NSLog(#"Discovered servicea: %#", peripheral.services);
for (CBService *service in peripheral.services) {
if ([service.UUID isEqual: [Utility SERVICE_UUID]]){
[peripheral discoverCharacteristics:#[[Utility UART_UUID]] forService:service];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
for (CBCharacteristic *aChar in service.characteristics)
{
if ([aChar.UUID isEqual:[Utility UART_UUID]])
{
#synchronized(self.writeLock)
{
self.uartCharacteristic = aChar;
//[peripheral readValueForCharacteristic:self.uartCharacteristic];
[peripheral setNotifyValue:YES forCharacteristic:self.uartCharacteristic];
}
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSString *tempStr = [[NSString alloc] initWithData: characteristic.value encoding: NSWindowsCP1252StringEncoding];
[delegate getDataFromPeripheral:peripheral Data:characteristic.value];
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
return;
}
}
And I am calling above class from NSOpeartion subclass
- (id)initWithConnectDevice:(ConnectDevice *)cDevice toPeripheral:(CBPeripheral *)peripheral{
if (self = [super init]) {
executing = NO;
finished = NO;
[[[AppDelegate app] connectDevices] setDelegate:self];
self.connectedPeripheral = peripheral;
deviceParticulars = [[DeviceParticulars alloc] init];
dataArray = [[NSMutableArray alloc] init];
dataString = [[NSMutableString alloc] init];
}
return self;
}
-(BOOL)isConcurrent{
return YES;
}
- (BOOL)isExecuting {
return executing;
}
- (BOOL)isFinished {
return finished;
}
-(void) terminateOperation {
[timer invalidate];
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
- (void)start {
#autoreleasepool {
if (self.isCancelled){
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
writableString = [[NSMutableString alloc] init];
[self createFile:[connectedPeripheral.identifier UUIDString]];
[[[AppDelegate app] connectDevices] calldiscoverServicesForPeripheral:connectedPeripheral];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}
-(void)timerFired:(id)sender{
if (self.isCancelled){
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
for (CBPeripheral *peripheral in [[AppDelegate app] peripheralsArray]) {
[[[AppDelegate app] connectDevices] writeDataToPeripheral:peripheral Data:[self dataFromText:#"#RAL$"]];
NSLog(#"Reading Peripheral::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::%#",[[AppDelegate app] peripheralsArray]);
}
}
I am allocating ConnectDevices class instance in Appdelegate. I am calling Nsoperation subclass from View Controller when BLE device is connected.
Problem, when i am writing data to one device it is working fine. But I connected to other device and write the data to second device i am getting bluetooth warning "is not valid characteristics for peripheral."
I think there is problem in my code.
Could you please help me
Please dont mind for this lot many lines of code.
many thanks

Create a separate model class for peripheral and call from my view controller. That solve my issue. Thanks a lot Paul.

Related

CoreBluetooth Framework: How to obtain connected devices without knowing the Service IDs?

I have a bluetooth bracelet which connects to my iPhone 5s via Bluetooth; it comes with an App called Zeroner. Now I want to obtain the information from the connected and paired up bracelet without using the App. Here is what I attempted to do:
Setup CBCentralManager
Use retrieveConnectedPeripheralsWithServices: to obtain connected devices
Here is the code:
CBConnectedDevicesVC.h
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import SERVICE_ID #"FB694B90-F49E-4597-8306-171BBA78F846"
#interface CBConnectedDevicesVC : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate>
#property (strong, nonatomic) CBCentralManager *centralManager;
#property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
#end
CBConnectedDevicesVC.m
#import "CBConnectedDevicesVC.h"
#implementation CBConnectedDevicesVC
- (void)viewDidLoad {
[super viewDidLoad];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
NSArray* connectedDevices = [_centralManager retrieveConnectedPeripheralsWithServices:#[[CBUUID UUIDWithString:SERVICE_UUID]]];
for (CBUUID *uuid in connectedDevices) {
NSLog(#"Device Found. UUID = %#", uuid);
}
}
}
#end
For the above codes, I have to specify the service ID in SERVICE_UUID, which I don't know what the value of the bracelet is. Is there any alternatives to obtain the information from the connected bracelet?
UPDATE about test result of LightBlue App
After unpaired from Zeroner App and "Forget this Device" in Settings > Bluetooth > choose the device named "Bracelet-0366", LightBlue App discovers the device (finally!).
Here is the result screenshot:
I got several values here, but I'm not sure which values I should use.
Further Test Results:
If I put the UUID (starts with 4EFF) found in LightBlue into SERVICE_ID, no delegate is called with the above codes.
Another piece of code I tried is (obtained from Tut+ tutorial):
NSArray *serviceID;
#implementation CBCentralManagerViewController
- (void)viewDidLoad {
[super viewDidLoad];
serviceID = #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
_data = [[NSMutableData alloc] init];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// You should test all scenarios
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
// Scan for devices
[_centralManager scanForPeripheralsWithServices:serviceID options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
NSLog(#"Scanning started");
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[_centralManager connectPeripheral:peripheral options:nil];
}
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(#"Failed to connect");
[self cleanup];
}
- (void)cleanup {
// See if we are subscribed to a characteristic on the peripheral
if (_discoveredPeripheral.services != nil) {
for (CBService *service in _discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
if (characteristic.isNotifying) {
[_discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
return;
}
}
}
}
}
}
[_centralManager cancelPeripheralConnection:_discoveredPeripheral];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"Connected");
[_centralManager stopScan];
NSLog(#"Scanning stopped");
[_data setLength:0];
peripheral.delegate = self;
[peripheral discoverServices:serviceID];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
// Discover other characteristics
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(#"Error");
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringFromData isEqualToString:#"EOM"]) {
[_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
[_centralManager cancelPeripheralConnection:peripheral];
}
[_data appendData:characteristic.value];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
return;
}
if (characteristic.isNotifying) {
NSLog(#"Notification began on %#", characteristic);
} else {
// Notification has stopped
[_centralManager cancelPeripheralConnection:peripheral];
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
_discoveredPeripheral = nil;
//
[_centralManager scanForPeripheralsWithServices:serviceID options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
}
With the above code, there are 2 constants defined TRANSFER_SERVICE_ID and TRANSFER_CHARACTERISTIC_ID. From the tutorial, the TRANSFER_SERVICE_ID should be set to the one starts with 4EFF and the TRANSFER_CHARACTERISTIC_ID should be set to 0xFF20 or FF20. However, this piece of code does not detect the bracelet at all, even though the bracelet is unpaired & disconnected. What did I miss this time?
Don't worry about the UUID that starts with 4EFF - this is the UUID of the device and will be different for each one.
The service id is FF20 - You can use this in scanForPeripheralsWithServices - this is SERVICE_ID in your code above.
Then you have two characteristics- FF21 and FF22
You can write to FF21 using the writeValue method on your CBPeripheral instance.
With FF22 that you can subscribe to notifications using the setNotify CBPeripheral method. You will then get a call to the didUpdateValueForCharacteristic CBPeripheralDelegate method whenever the device changes the value.
There are 2 types of bluetooth devices you can work with:
BLE devices - no need (often can't) to pair them with iPhone
"standard" bluetooth devices - you need to pair them with iPhone before use
Those two types are managed independently - from the way you described it I expect your bracelet to fall into "standard" category, and CoreBluetooth can only be used for BLE.
For working with already paired external accessories you should use ExternalAccessory framework

CoreBluetooth: Attempt to write to device

I have a connected & paired up Bluetooth LE bracelet (Service ID: FF20), which have 2 characteristics:
0xFF21 : Write without Response
0xFF22 : Notify
Now I try to write data via CoreBluetooth Framework to 0xFF21 with the following code:
I defined 2 constants at header file:
#define TRANSFER_SERVICE_UUID #"FF20"
#define TRANSFER_SERVICE_CHARACTERISTIC_UUID #"FF21"
.m
- (void)viewDidLoad {
[super viewDidLoad];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
NSArray* connectedDevices = [_centralManager retrieveConnectedPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
for (CBPeripheral *peripheral in connectedDevices) {
NSLog(#"Device Found. CBPeripheral = %#", peripheral);
peripheral.delegate = self;
if(peripheral.services.count == 0) {
NSLog(#"No service found");
}
for (CBService *service in peripheral.services) {
if(service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
// check notifying ?
NSData *data = [#"Testing" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} else {
NSLog(#"Specific Characteristic Not found");
}
}
} else {
NSLog(#"Characteristic is NULL");
}
}
}
}
}
The log appears:
Device Found. CBPeripheral = <CBPeripheral: 0x1740f5080, identifier = 4EFF694C-017A-536F-9301-2EB2CC316CBE, name = Bracelet-0366, state = disconnected>
No service found
What did I miss?
You need to issue a connect to the discovered peripheral and get a call to your didConnectPeripheral delegate method before you can issue read/write requests.
When you reach the poweredOn state you should issue a scanForDevicesWithServices call, wait for the call back to your delegate, then connect, discover the service and characteristics, then you can issue a write.
-(void) centralManagerDidUpdateState:(CBCentralManager *)central {
switch (central.state) {
case CBCentralManagerStatePoweredOn:
[central scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] options:nil];
break;
}
}
-(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered peripheral %# (%#)",peripheral.name,peripheral.identifier.UUIDString);
if (self.connectedPeripheral == nil) {
[central connectPeripheral:peripheral options:nil];
}
}
-(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
self.connectedPeripheral=peripheral;
NSLog(#"Connected to %#(%#)",peripheral.name,peripheral.identifier.UUIDString);
peripheral.delegate=self;
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]];
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
NSLog(#"Discovered service %#",service.description);
[peripheral discoverCharacteristics:nil forService:service];
}
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics ) {
NSLog(#"Discovered characteristic %#(%#)",characteristic.description,characteristic.UUID.UUIDString);
if ([characteristic.UUID.UUIDString isEqualToString:TRANSFER_SERVICE_CHARACTERISTIC_UUID) {
NSData *data = [#"Testing" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}
}
}
Note, that from your previous question the characteristic only supports write without response, so you can't use CBCharacteristicWriteWithResponse

Core bluetooth ios 8

I use Core Bluetooth to connect two ios devices. Everything is working perfect for ios 7, but for ios 8 no. Device with ios 8 is not visible as peripheral device.
Some code:
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
[_peripheralManager startAdvertising:#{CBAdvertisementDataServiceUUIDsKey: #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]}];
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
}
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if(error){
[self cleanup];
return;
}
for (CBCharacteristic *charactristic in service.characteristics) {
if ([charactristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:charactristic];
}
}
}
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
[_centralManager cancelPeripheralConnection:peripheral];
[_data appendData:characteristic.value];
NSDictionary *recievedData = [NSDictionary dictionaryWithObject:stringFromData forKey:#"receivedData"];
[[NSNotificationCenter defaultCenter]
postNotificationName:DATA_FROM_PERIPHERAL_RECEIVED
object:self userInfo:recievedData];
// }
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
return;
}
if (characteristic.isNotifying) {
NSLog(#"Notification began on %#", characteristic);
}else{
[_centralManager cancelPeripheralConnection:peripheral];
}
}
iOS 8.0 bluetooth peripheral manager giving no callback for addService - This question helps me to fix this issue. Just need to move
[_peripheralManager startAdvertising:#{CBAdvertisementDataServiceUUIDsKey: #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]}];
to -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral method:
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
return;
}
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
[_peripheralManager startAdvertising:#{CBAdvertisementDataServiceUUIDsKey: #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]}];
self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];
CBMutableService *transferService = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];
transferService.characteristics = #[_transferCharacteristic];
[_peripheralManager addService:transferService];
}
}
Now everything works great for ios 6,7,8.

Corebluetooth disconnecting just after the connection

I'm actually to exchange informations between an iPhone and an iPad using Corebluetooth.
My iPhone act as the Central and my iPad as the Peripheral.
I'm advertizing my service but on my central when i'm going through the :
peripheral:didDiscoverServices:
the peripheral.services that I get in that method is empty.
and some seconds after i'm disconnecting from the peripheral with this error :
DISCONNECT-ERROR desc : Error Domain=CBErrorDomain Code=7 "The specified device has disconnected from us." UserInfo=0x16e60f90 {NSLocalizedDescription=The specified device has disconnected from us.}
I don't know what is going on.
EDIT:
on the Central side I have this :
-(void)startScanning{
[super startScanning];
// Scan for devices
[self.centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:PERIPHERAL_SERVICE_UUID]] options:nil];
}
#pragma mark Peripheral Delegate
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:NEW_COMMANDS_NOTIFIER_CHARACTERISTICS_UUID]] forService:service];
}
// Discover other characteristics
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBCharacteristic *characteristic in service.characteristics) {
if (self.commandsFromIpadCharacteristic != characteristic) {
self.commandsFromIpadCharacteristic = characteristic;
}
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:NEW_COMMANDS_NOTIFIER_CHARACTERISTICS_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
On the Peripheral side I have :
#pragma mark CBPeripheralManagerDelegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
return;
}
if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
self.datasFromIphoneCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:NEW_DATAS_FROM_IPHONE_CHARACTERISTICS_UUID] properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable];
self.commandNotifierCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:NEW_COMMANDS_NOTIFIER_CHARACTERISTICS_UUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];
CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:PERIPHERAL_SERVICE_UUID] primary:YES];
transferService.characteristics = #[self.datasFromIphoneCharacteristic, self.commandNotifierCharacteristic];
[self.peripheralManager addService:transferService];
[self.peripheralManager startAdvertising:#{CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:PERIPHERAL_SERVICE_UUID]]}];
}
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error {
if (error) {
NSLog(#"Error advertising: %#", [error localizedDescription]);
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
if (characteristic == self.commandNotifierCharacteristic){
// on envoie le message au delegate
if([[self delegate] respondsToSelector:#selector(iPhoneIsConnectedToIpad:)]) {
[[self delegate] iPhoneIsConnectedToIpad:YES];
}
}
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
if (characteristic == self.commandNotifierCharacteristic){
// on envoie le message au delegate
if([[self delegate] respondsToSelector:#selector(iPhoneIsConnectedToIpad:)]) {
[[self delegate] iPhoneIsConnectedToIpad:NO];
}
}
}
EDIT ANSWER :
I found the problem, In the centralManager:didConnectPeripheral: I wasn't calling the right service UUID with [peripheral discoverServices:]. Thank you for your help :).
I found the problem, In the centralManager:didConnectPeripheral: I wasn't calling the right service UUID with [peripheral discoverServices:]. Thank you for your help :).

CBCentralManager connecting to a CBPeripheralManager, connects then disconnects?

I have an iOS device (iPod Touch 5G) acting as a CBCentralManager, and Bluno acting as a CBPeripheralManager. When I attempt to connect to the peripheral with the central it appears to connect for a second or two then disconnects. I can see a LED on the Bluno light up for a second or two then dim down. I know there isn't a problem with the Bluno because I can use the LightBlue app on the iPod Touch to connect to the peripheral. So the problem probably lies somewhere in my code.
As of right now, I am getting the following message when I status syslog,
CoreBluetooth[WARNING] <CBCentralManager: 0x16e77470> is disabling duplicate filtering, but is using the default queue (main thread) for delegate events
Not sure if that is related to the connect / disconnect problem.
The code I have constructed is as follows,
Services.h
#define BLUNO_TRANSFER_SERVICE_UUID #"0xDFB0"
#define BLUNO_TRANSFER_CHARACTERISTIC_UUID #"0xDFB2"
ViewControllerDev2.h
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <QuartzCore/QuartzCore.h>
#import "SERVICES.h"
#interface ViewControllerDev2 : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate, UITextViewDelegate> {
}
#property (weak, nonatomic) IBOutlet UIBarButtonItem *btnDone;
// Core Bluetooth Peripheral stuff
#property (strong, nonatomic) CBCentralManager *centralManager;
#property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
#property (strong, nonatomic) NSMutableData *data;
#property (strong, nonatomic) IBOutlet UITextView *textView;
#property (weak, nonatomic) IBOutlet UIButton *btnSend;
- (IBAction)dismissScene:(id)sender;
- (IBAction)sendBTData:(id)sender;
#end
ViewControllerDev2.m
#import "ViewControllerDev2.h"
#implementation ViewControllerDev2
- (void)viewDidLoad
{
[super viewDidLoad];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil]; // options:nil is an iOS 7 feature
_data = [[NSMutableData alloc] init];
}
- (void)viewDidUnload {
[self setBtnDone:nil];
[super viewDidUnload];
}
- (IBAction)sendBTData:(id)sender {
//[self sendData];
}
- (IBAction)dismissScene:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
[_centralManager stopScan];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
// You should test all scenarios
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
// Scan for devices
[_centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:BLUNO_TRANSFER_SERVICE_UUID]] options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
NSLog(#"Scanning started");
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[_centralManager connectPeripheral:peripheral options:nil];
// then stop scanning for peripherals
[_centralManager stopScan];
NSLog(#"Scanning stopped");
}
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(#"Failed to connect");
[self cleanup];
}
- (void)cleanup {
// See if we are subscribed to a characteristic on the peripheral
if (_discoveredPeripheral.services != nil) {
for (CBService *service in _discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BLUNO_TRANSFER_CHARACTERISTIC_UUID]]) {
if (characteristic.isNotifying) {
[_discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
return;
}
}
}
}
}
}
[_centralManager cancelPeripheralConnection:_discoveredPeripheral];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"Connected");
[_centralManager stopScan];
NSLog(#"Scanning stopped");
[_data setLength:0];
peripheral.delegate = self;
[peripheral discoverServices:#[[CBUUID UUIDWithString:BLUNO_TRANSFER_SERVICE_UUID]]];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:BLUNO_TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
// Discover other characteristics
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BLUNO_TRANSFER_CHARACTERISTIC_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(#"Error");
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringFromData isEqualToString:#"EOM"]) {
//[_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
[_centralManager cancelPeripheralConnection:peripheral];
}
[_data appendData:characteristic.value];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:BLUNO_TRANSFER_CHARACTERISTIC_UUID]]) {
return;
}
if (characteristic.isNotifying) {
NSLog(#"Notification began on %#", characteristic);
} else {
// Notification has stopped
[_centralManager cancelPeripheralConnection:peripheral];
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
_discoveredPeripheral = nil;
[_centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:BLUNO_TRANSFER_SERVICE_UUID]] options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
}
#end
Here's your problem:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[_centralManager connectPeripheral:peripheral options:nil]; // <-- this is the issue
// then stop scanning for peripherals
[_centralManager stopScan];
NSLog(#"Scanning stopped");
}
}
You're connecting to a weakly held object, you should connect to your _discoveredPeripheral object instead. Also, don't forget to update your property calls to use your BCPeripheral object, for example:
[_discoveredPeripheral discoverServices:#[[CBUUID UUIDWithString:BLUNO_TRANSFER_SERVICE_UUID]]];

Resources