IPhone does not detect services on Bluetooth LE shortcut when reconnecting

I am working on a Bluetooth LE app for iOS. I use the basic bluetooth infrastructure in iOS to process all messages.

Question and description:

When I use one tag, despite numerous connections and disconnections, one tag connects without problems, and the phone detects its services.

In addition, when several Bluetooth LE shortcuts are connected for the first time, they are easily connected and the phone detects their services. When the tags are disconnected and then reconnected to the phone, the tags connect normally. But one of the two tags (one of them) does not seem to advertise its services. that is, when the application is open and the tag reconnects, the DiscoverServices method does not call the didDiscoverServices delegate.

Why does this happen only when there is a connection with several devices.

I installed peripheral.delegate correctly. I tried everything, including reconnecting, repeated DiscoverServices calls to the tag. Nothing seems to work.

How can I reconnect to multiple tags on the phone and still open all the services.

Please, help

Thanks,
Manzhu

+8
iphone xcode ios5 bluetooth core-bluetooth
source share
8 answers

It turns out that there was a command that I issued to the device in the didDiscovercharacteristicsForService delegate method , which caused the connection to become unstable.

If you encounter such problems, I suggest you complete the delegation process without any intervention (of any type ) and pass CBPeripheral to another function that you developed to pass any values โ€‹โ€‹/ issue a device command.

Anyway, thanks.

So, the steps are as follows.
1> Tag Search,
2> If in range, CONNECT to Tag
3> If connected, call the DISCOVER services method (do not interrupt)
4> IN DidDiscoverServices, DISCOVER call Characteristics Method
..
In the DidDiscoverCharacteristics method, wait until all signs are detected. Then, at the end, call the function in your code that will make the necessary settings.

...
Code example

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { for (int i=0; i < peripheral.services.count; i++) { CBService *s = [peripheral.services objectAtIndex:i]; printf("Fetching characteristics for service with UUID : %s\r\n",[self CBUUIDToString:s.UUID]); [peripheral discoverCharacteristics:nil forService:s]; } } - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if (!error) { CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)]; if([self compareCBUUID:service.UUID UUID2:s.UUID]) { // This is when the **Tag** is completely connected to the Phone and is in a mode where it can accept Instructions from Device well. printf("Finished discovering characteristics"); // Now Do the Setup of the Tag [self setupPeripheralForUse:peripheral]; } } else { printf("Characteristic discorvery unsuccessfull !\r\n"); } } -(void) setupPeripheralForUse:(CBPeripheral *)peripheral { // DO all your setup in this function. Separate Perpiheral Setup from the process that synchronizes the tag and the phone. } 
+1
source share

I had the same problem, but I realized that after <<22> I did not install delegate in CBPeripheral .

 - (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"Peripheral Connected: %@", peripheral.name); peripheral.delegate = self; if (peripheral.services) { [self peripheral:peripheral didDiscoverServices:nil]; } else { [peripheral discoverServices:@[[CBUUID UUIDWithString:CUSTOM_UUID]]]; } } 
+20
source share

I had a similar problem with CoreBluetooth for connecting to Bluetooth LE devices, in my case connecting to iOS devices (peripherals) from my Mac (central).

If I understand you correctly, the template is quite consistent, the first time I run the Mac application for debugging, it is always detected and connected to any Bluetooth devices (peripherals), most importantly, it also detects their services / features well. The problem starts in the second run (for example, change the code, press cmd-R to restart debug). The center still detects peripheral devices and connects to them, but does not detect any services / features. In other words, the delegate peripheral:didDiscoverServices: and peripheral:didDiscoverCharacteristicsForService:error: will never be called.

The solution after a lot of trial and error is surprisingly simple. It seems that CoreBluetooth caches services and characteristics for peripherals that are still connected, although locally it looks like it was disconnected from the application, the peripheral device still supports Bluetooth connectivity to the system. For these types of connections, there is no need to (re) detect services and characteristics, just access them directly from the peripheral object, check nil to see if they should be detected. In addition, as already mentioned, since the peripheral device is in a state between connections, it is best to call cancelPeripheralConnection: right before trying to connect. Its essence is as follows: suppose that we have already discovered a peripheral connection with:

 -(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { [central cancelPeripheralConnection:peripheral]; //IMPORTANT, to clear off any pending connections [central connectPeripheral:peripheral options:nil]; } -(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { peripheral.delegate = self; if(peripheral.services) [self peripheral:peripheral didDiscoverServices:nil]; //already discovered services, DO NOT re-discover. Just pass along the peripheral. else [peripheral discoverServices:nil]; //yet to discover, normal path. Discover your services needed } -(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { for(CBService* svc in peripheral.services) { if(svc.characteristics) [self peripheral:peripheral didDiscoverCharacteristicsForService:svc error:nil]; //already discovered characteristic before, DO NOT do it again else [peripheral discoverCharacteristics:nil forService:svc]; //need to discover characteristics } } -(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { for(CBCharacteristic* c in service.characteristics) { //Do some work with the characteristic... } } 

This works well for me for the CBCentralManager app on Mac. I have never tested it in iOS, but I assume that it should be very similar.

+11
source share

I do everything you say in your answer, but I still see this question from time to time. My guess is that Core Bluetooth is getting into a weird state, probably due to a specific connection, subscription and disconnect sequence.

The only way I decided to fix this problem is to restart the iOS device. However, this problem can be fixed in iOS 7.1.

0
source share

I had the same problem. this seems to happen about 1/3 times in my case. I tried the solution provided by PL but I was not successful in iOS. There may be a lot of moving parts here that can help solve this problem (flashing a Bluetooth device, CoreBluetooth, etc.), but I solved it by simply tracking devices that are waiting for services / signs to be detected in NSMutableDictionary, and using GCD to check if it completed its detection within a reasonable time and try again if necessary. So something like this:

 - (void)requestDiscoverServicesForPeripheral:(CBPeripheral *)peripheral { peripheral.delegate = self; NSString *uuid =[self stringUUIDForUUID:peripheral.UUID]; NSLog(@"discovering %d services ", self.interestingServices.count); [peripheral discoverServices:self.interestingServices]; [self.pendingConnectionDevices setObject:peripheral forKey:uuid]; __weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 *NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if ([weakSelf.pendingConnectionDevices objectForKey:uuid]) { //request discover services again NSLog(@"services did not discover, requesting again!"); [weakSelf.btManager cancelPeripheralConnection:peripheral]; [weakSelf.btManager connectPeripheral:peripheral options:nil]; } }); } 

Then, when peripheral:didDiscoverServices:error accessed back, I remove it from my pending connection dictionary. It seems to work very well. I saw how he tried to discover services up to 3 times before succeeding. Hope this helps.

0
source share

Sometimes this is a hardware problem. I just came across a situation where the hardware enters sleep mode, which can be scanned, connected, but not sent at all to DiscoverServices.

There was also a situation that happened to me when developing BLE all night and all of a sudden, the device became silence for DiscoverServices, no matter what I did. Finally, I found that it would be okay if I reboot my iPhone5.

And once a Bluetooth hardware engineer told me that the BLE specification only says that the device must be connected again within 30 seconds. Therefore, if I connect and disconnect again and again, it may not work as expected ... which I still doubt it.

0
source share

My headache was caused by a lack of strong peripheral links

So I added the link and the problem disappeared

 private var activePeripheral: CBPeripheral? func connect(_ peripheral: CBPeripheral) { disconnect(peripheral) activePeripheral = peripheral self.central.connect(peripheral, options: nil) } 
0
source share

I tried to apply all of the above answers, but it did not work for me because I was missing CBPeripheralDelegate in the class.

 class BLEHandler : NSObject, CBCentralManagerDelegate, CBPeripheralDelegate{ func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices(nil) print("Connected: \(peripheral.state == .connected ? "YES" : "NO")") } func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { for service: CBService in peripheral.services! { peripheral.discoverCharacteristics(nil, for: service) print(service) } } } 
0
source share

All Articles