Bluetooth Low Energy Peripheral communicate with iPhone SDK - ios

I have one Bluetooth LE device, I need to scan it only, that I have done with Core Bluetooth Framework in iPhone SDk.
Below is sample code,
manager is object of CBCenterManager which writes in the init method:
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
scanning process:
- (void)startScan
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
manager.delegate = self;
[manager scanForPeripheralsWithServices:nil options:options];
}
Now I got that device in delegate methods,
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"Did discover peripheral. peripheral: %# rssi: %#, UUID: %# advertisementData: %# ", peripheral, RSSI, peripheral.UUID, advertisementData);
}
**Here I have write only few lines of code,
This is not enough data for me to show in interface. Because peripheral.UUID is unique for each device, if I change device to discover BLE, it will be changed.
So I want unique address of Bluetooth LE device which I got same in every iOS devices.
Like peripheral.UUID is 1FE639DB-3C54-B5A8-74A4-3D9FBFCAD074
I had discover same thing in android got address like C8:4D:93:78:98:AE this.
and its unique for all android devices,
So I am searching for the same thing in iPhone SDK.
Is it possible to get same unique address of Bluetooth LE in iPhone SDK?
Thanks for your time to read questions.

Related

IOS BLE connection gets disconnected continuously

IOS application is communicating with BLE peripheral using Core-Bluetooth framework. The app has registered for glucose characteristic and is receiving data from the peripheral after every one minute.
It is being observed that, when the application is in idle state there is no disconnection from the BLE peripheral whereas if I navigate between the ViewControllers present in the application then there happens to be continuous disconnection with the BLE peripheral.
The connection parameters set are within the given range as mentioned in Apple's Core-Bluetooth programming guide. Any ideas why the connection keeps on getting disconnecting?
I had also used the BTLE Transfer Source Code present in apple developer site. And had replaced the Transfer service UUID with Glucose service UUID. I had tested this on iPhone 6 with iOS version 8.3. I am still facing the same issue of disconnection.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
if (self.discoveredPeripheral != peripheral) {
self.discoveredPeripheral = peripheral;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[self.centralManager stopScan];
[self.data setLength:0];
peripheral.delegate = self;
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}
check you don't explicitly use weak properties to manage your peripherals (by default types are strong), check this issue.
However without any piece of code all I can suggest is to grab a BLE packet sniffer and see who, when and therefore why it sends the disconnection command. In this process beware about the channel hopping, you have 1/3 of chances to capture the channel with the sniffer so just retry until you see the data flow on the screen. If not now, it's always welcome to have a device like that if you will regularly work with Bluetooth Low Energy.
// method called whenever you have successfully connected to the BLE peripheral
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
self.myPeripheral = peripheral;
self.myPeripheral.delegate = self;
NSString *connected = [NSString stringWithFormat:#"Connected: %#", peripheral.state == CBPeripheralStateConnected ? #"YES" : #"NO"];
NSLog(#"%#", connected);
}
Put this method,
Note: It is a good practice to assign your discovered peripheral to a retained CBPeripheral into centralManager: didConnectPeripheral
//this one line code stops disconnecting device automatically.
[[Manager sharedManager].connected_PeripheralDevice discoverServices:nil];

iOS does not detect new peripheral name

We are using CC2540 BLE Chip as peripheral and an iOS 7.0.4 iPhone is playing central role.
We change the peripheral name, but this change is only shown when we disconnect from iOS device and reconnect.
It works fine in Android using this code to change peripheral name in response data:
GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( deviceName ), deviceName );
We are using this code to change the peripheral name of GAP layer in iOS:
GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );
Is there any way to change peripheral name so that no reconnection is needed?
For me the problem is in the iOS App code.
The basic order of calls to connect in iOS to BLE is:
centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil
options: nil];
this last one invokes:
- (void) centralManagerDidUpdateState:(CBCentralManager *)central
then if central.state is CBCentralManagerStatePoweredOn you can:
[centralManager scanForPeripheralsWithServices:nil
options:nil];
this last one invokes:
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
Apple here recommends: "You must retain a local copy of the peripheral if any command is to be performed on it."
That means you should create a property for your CBPeripheral like:
self.myPeripheral = peripheral;
It is here where you have a peripheral.name or self.myPeripheral.name
If you don't call again in your code: [centralManager scanForPeripheralsWithServices:nil options:nil]; what you have is the information retrieved the first time. You should make the call again if you want to refresh the name. Maybe with a timer.
Hope that helps.
EDIT
Check: Core Bluetooth Programming Guide: Performing Common Central Role Tasks
you can get the local name from advertisementData. There is the solution: Incorrect BLE Peripheral Name with iOS
And on Apple Developer Forums, here is the detail of CBPeripheral name property.

Run iOS 6 device as a BLE peripheral

As we know, iOS 6 support running devices (iPhone 4s and above, and new iPad) as a BLE peripheral. There is a demo in WWDC 2012 Session 705 called "advanced core bluetooth". I asked for the source code from Apple. They sent me a modified version of source code (BTLE_Transfer_Draft). Then I:
Run the app in iPhone 5 (iOS 6) in "Peripheral Mode" and start "Advertising"
Run the app in new iPad (iOS 5.1.1) in "Central Mode"
The problem is that the peripheral is never been discovered at all. So I use other testing applications including some downloaded from App Store. All failed to discover peripherals. I think the problem should be in BTLE_Transfer_Draft. Because I'm not sure whether I'm allowed to present the whole source code. So I just show the "peripheral mode" part here:
- (void)viewDidLoad {
[super viewDidLoad];
// Start up the CBPeripheralManager
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
// Opt out from any other state
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
return;
}
// We're in CBPeripheralManagerStatePoweredOn state...
NSLog(#"self.peripheralManager powered on.");
// ... so build our service.
// Start with the CBMutableCharacteristic
self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
// Then the service
CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]
primary:YES];
// Add the characteristic to the service
transferService.characteristics = #[self.transferCharacteristic];
// And add it to the peripheral manager
[self.peripheralManager addService:transferService];
}
/** Start advertising
*/
- (IBAction)switchChanged:(id)sender
{
if (self.advertisingSwitch.on) {
// All we advertise is our service's UUID
[self.peripheralManager startAdvertising:#{ CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
}
else {
[self.peripheralManager stopAdvertising];
}
}
The BLE is in powered on status and the startAdvertising is called. But the BLE central can never discover it.
Post updated:
According to mttrb's suggestion I added "CBAdvertisementDataLocalNameKey" when I startAdvertising. But my service is still can't be discovered by most of the apps including some apps from app store. The only one app can discover my service is an app from app store called "BLE scanner".
My question is: does this mean my application is working as a peripheral? But why my own code can't discover the service? How am I supposed to debug it ?
My code in Central Mode is like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Start up the CBCentralManager
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
......
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error) {
NSLog(#"Error discovering services: %#", [error localizedDescription]);
return;
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Deal with errors (if any)
if (error) {
NSLog(#"Error discovering characteristics: %#", [error localizedDescription]);
return;
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"Peripheral Disconnected");
self.discoveredPeripheral = nil;
}
The didDiscoverPeripheral and didDiscoverServices are never called. What could be wrong? Any idea? Thanks
There is also a high quality free app called LightBlue that you can use to test your code with. It should be able to pick up all devices advertising in peripheral mode and it can even turn itself into an advertising peripheral if you want to make sure your device is working properly.
I would try moving the startAdvertising: method call up and into the end of your peripheralManagerDidUpdateState: delegate method and see if that helps.
I would also add a CBAdvertisementDataLocalNameKey key-value pair to your startAdvertising: method call. I found things were unreliable when the advertisement didn't have a name.
Finally, I would invest in the BLExplr app available in the App Store to help with scanning for your peripheral. It removes the assumption that your central is working correctly.
This Git hub project also throws some light on the CBPeripheralManager API. Called PeripheralModeTest.
This line is particularly useful for setting the advertising data
NSDictionary *advertisingData = #{CBAdvertisementDataLocalNameKey : #"Device Name", CBAdvertisementDataServiceUUIDsKey : #[[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]]};
Though I can't see any official documentation in the Apple iOS Developer Library yet. More specifically anything about setting the repeat period for the advertising.
The BTLE Transfer example has this piece of (odd) code, which may cause some troubles:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
// Reject any where the value is above reasonable range
if (RSSI.integerValue > -15) {
return;
}
// Reject if the signal strength is too low to be close enough (Close is around -22dB)
if (RSSI.integerValue < -35) {
return;
}
Just remove those two if-statements as it makes no sense!
I have made a simplified version available here that can be used to test high volumes of messages being sent from peripheral to central.
Please note that the CBPeripheralManager class was first introduced in iOS 6.0.
I do not know witch version of BTLE Central Peripheral Transfer you did actually test but current version has iOS 6 as requirement.
So I would suggest to test linkage against iOS 5.1 to see what compatibility issues it shows.

Cannot find peripheral when scanning for specific service CBUUID

When I use:
CBUUID * uuid = [CBUUID UUIDWithString:#"1800"]; // GAP
DEBUG_LOG(#"CBUUID: %#",uuid); // CBUUID: Generic Access Profile
_centralMan = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[_centralMan scanForPeripheralsWithServices:[NSArray arrayWithObject:uuid]
options:nil];
I cannot find my peripheral, but when I use:
_centralMan = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[_centralMan scanForPeripheralsWithServices:nil
options:nil];
…it shows up immediately.
When I connect, I am able to discover/read/write to all the services I am expecting. My understanding is that GAP makes this possible. I have also tried CBUUID's for other services that I know are running (specifically "1804", TX power service), to no avail; the scan never discovers anything.
Even though the services are running (I can communicate w/ them upon connecting), when I scan passing the service UUID array as nil and this delegate method is called...
-(void) centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
DEBUG_LOG(#"Found peripheral w/ UUID: %# RSSI: %# \n AdvData: %#",peripheral.UUID,RSSI,advertisementData);
DEBUG_LOG(#"Services found: %d",peripheral.services.count);
for (CBService * service in peripheral.services) {
DEBUG_LOG(#"Found service: %# w/ UUID %#",service, service.UUID);
}
}
…it always reports "Services found: 0". Should I expect the services array to be populated w/ services found during the scan? (I assume this is at least partially possible, based on scanForPeripheralsWithServices:[NSArray arrayWithObject:uuid]
options:nil.)
Could this be a problem w/ my peripheral's service advertisements? Am I using the API incorrectly? Any guidance is much appreciated! :-)
PS: I'm pretty green w/ Bluetooth.
PPS: I control the source to the peripheral (it's a CC2540DK). So I'd be as likely to believe the problem is there as it is here.
Turns out our peripheral code was not advertising the UUIDs a la this Bluetooth spec.
As soon as we dropped them into the advertising packet, iOS picked them up no sweat.

Core Bluetooth - constant RSSI updates of in-range devices

I just started with the core bluetooth framework for iOS and I'm developing an app that needs to constantly scan for BLE devices so that I can retrieve their RSSI number every minute or so.
Currently I have:
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[manager scanForPeripheralsWithServices:nil options:options];
this starts my app scanning for BLE devices and calls this delegate method when a device is discovered:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Did discover peripheral. peripheral: %# rssi: %#, UUID: %# advertisementData: %# ", peripheral, RSSI, peripheral.UUID, advertisementData);
//Do something when a peripheral is discovered.
rssiLabel.text = [RSSI stringValue];
[manager retrievePeripherals:[NSArray arrayWithObject:(id)peripheral.UUID]];}
this method gets me the peripheral's RSSI number which i can display. The last line then calls this delegate method:
- (void) centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals {
NSLog(#"Currently known peripherals :");
int i = 0;
for(CBPeripheral *peripheral in peripherals) {
NSLog(#"[%d] - peripheral : %# with UUID : %#",i,peripheral,peripheral.UUID);
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[manager scanForPeripheralsWithServices:nil options:options];
}
This code seems to be working and doing a scan roughly every 1 minute, but I don't exactly know why it working...
The documentation on core bluetooth is pretty sparse so if anyone has any idea on how to do this, or has a better way to do what I'm trying to accomplish I'd appreciate the help!
Have you tried changing the scan option to YES?
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[manager scanForPeripheralsWithServices:nil options:options];
If you do this you will get your "didDiscoverPeripheral" callback with every ad packet that is seen by your iPhone, which would normally be about every 100ms (although I see this callback timing varying a lot for the same device). This includes the RSSI of each device it sees.
This should be a lot faster than your ~1 minute update rate.
Is far as I can see, this should do what you want.
When you started scanning for peripherals with the original call, your delegate should begin to get calls whenever a BLE device is discovered. This will continue until you stop the scan with a call to
[manager stopScan];
I don't think you actually need the second call to scanForPeripheralsWithServices in your centralManager:didRetrievePeripherals method, since, as far as I know, the scanning doesn't stop until you tell it to. I'm still getting started on this, too, though, and there may be a timeout I have not found, yet.
I'm pretty sure the reason you get a call about once a minute is because the BLE device is only advertising that often. If it advertises more often, like a device in discovery mode, I think you will get the calls more often. I would be interesting if you could confirm that. If the device has a discovery mode, you might try triggering it to see if the notices speed up.
You shouldn't do continous scanning as it is very costly for power. Once you discovered devices you have an array of CBPeripheral objects returned to you. On CBPeripheral you can read RSSI and get a callback when RSSI changes. See the following documentation:
http://developer.apple.com/library/mac/#documentation/CoreBluetooth/Reference/CBPeripheralDelegate_Protocol/translated_content/CBPeripheralDelegate.html
Swift Implementation of #Anders solution:
manager.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : NSNumber(value: true)])

Resources