Sometimes in random moments (usually after background disconnect) I have a strange bug with connection
WARNING: <CBPeripheral: 0x1c4109ea0, identifier = 6040FFF8-6E53-4776-ABF7-9632093B2DB5, name = XXXXXXXX, state = connecting> is not a valid peripheral
I checked connection status on BLE device and app was connected but didn't subscribe for notifications. On app, state was connecting. The only way to reconnect properly after this bug is to close and open app again.
What can I do to prevent this situation?
Please make sure, if you are connecting any BLE device multiple times, then before connecting device again it should be disconnected. As From your scenario, it seems that you are connecting a BLE device again n again without disconnecting it.
Related
I am using CoreBluetooth for IOS app, after upgrading IOS version the central manager canĀ“t connect to peripheral and not showing any error.
Before starting te process to connect I receive this values from the device:
CBPeripheral: 0x1c0106e40, identifier = BE2B06BF-F385-82AC-95E6-65EA1CF8B11F, name = icomon, state = disconnected
and after I try to connect to the device the state changes:
CBPeripheral: 0x1c411bea0, identifier = BE2B06BF-F385-82AC-95E6-65EA1CF8B11F, name = icomon, state = connecting
and nothing more, nothing happen next, I do not receive any data from the central manager and the device state never change.
I was struggling with a problem that has the exact same symptoms. Hopefully it is the same problem, and this response is helpful.
In my case, the problem was caused by a link layer control PDU that my device was sending immediately after the connection was established. Specifically, I am running Apache Mynewt (http://mynewt.apache.org/), and its NimBLE controller initiates the Feature Exchange Procedure immediately after a connection is made. Since my device is the peripheral, while the iOS 11 device is the central, my device sends the LL_SLAVE_FEATURE_REQ PDU.
I don't know if it is the timing involved or the PDU itself, but whatever the case, the iOS device never sends any application-layer data after the feature exchange. When I change NimBLE so that it does not initiate the feature exchange, device interrogation happens normally, and the CoreBluetooth connected callback gets called.
I have a use case where my objective-c application needs to immediately use iBeacon after it's been terminated in order to wake the application up from a terminated state, connect to BLE and send a command to the device. I have a larger longer running post found here that you can check out for my code if need be.
The Problem
The problem so far, happens when I run the application, search for previously paired devices and/or scan for peripherals, find my BLE device and connect. Once connected the user pairs the BLE connection so that they can send encrypted characteristic data over BLE connection. Without pairing (aka auth/bond in the device's naming conventions) the user cannot send the data to the device at all. It never makes it there. As soon as you pair you can send the command...
When I terminate the app, in the applicationWillTerminate method, I run through this code...
- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(#"*** Application Will Terminate.");
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSNumber *mode = [userDefaults objectForKey:#"deviceConnectedMode"];
if([mode intValue] == CONNECTED_MODE_INDICATOR) {
[self.bluetoothManager sendCodeToBTDevice:#"magiccommand1"
characteristic:self.bluetoothManager.wipeCharacteristic];
//I have been turning this command on and off in testing to see if I can get it to work better while disconnecting in the device rather than in the app...
//The command magiccommand2 wipes the auth/bond inside of the device
// [self.bluetoothManager sendCodeToBTDevice:#"magiccommand2"
// characteristic:self.bluetoothManager.disconnectCharacteristic];
//Place where I attempt to stop being connected to BT
[self.bluetoothManager disconnectDevice];
[self.beaconManager startMonitoring];
NSLog(#"*** Application terminated from connected mode!");
} else {
NSLog(#"*** DriveCare terminated without violation!");
}
}
What I am trying to accomplish
The magiccommand1 and magiccommand2 commands are just silly test strings (for now, 128 bit tokens later) that the device is listening for over the serial port. Once they receive the commands they react by attempting to wipe the auth/bond on the device and also disconnecting from BLE in the device.
So the only way I can seem to get the app to wake up from a terminated state is with iBeacon. So I am having to do a bunch of seemingly dirty stuff here just to get this round peg in a square hole. In the app's lifecycle it connects and pairs and when I terminate I want it to completely be removed as a connected device from BLE. My hope is that iBeacon will wake up the app, connect back to BLE, shut off iBeacon monitoring and then send a command to the BLE device from a terminated state. This turning on/off or connecting/disconnecting from iBeacon to BLE and back would most likely cause the user to have to re-pair and I don't want this.
More Problems
When I call [self.centralManager cancelPeripheralConnection:self.thePeripheral]; the iOS system level BT manager seems to auto reconnect almost instantly (because of the pairing) so there is no time for the connection to be severed and iBeacon to be picked up again. If I attempt to disconnect from my centralManager instance before sending the disconnect command to my box (as seen above in code commented out) they obviously wont send either. If I just use only that CBCentralManager disconnect method it isn't enough for iBeacon to begin being detected as the iOS system is still paired with the device. Lastly, if I then go into my iOS system BT manager and choose "Forget this device", the iBeacon gets picked up again and my didEnterRegion method fires!
This is a lot of back and forth between iBeacon and BLE and I just wish I didn't even need iBeacon to wake up the app. I have all info.plist background BLE and iBeacon services turned on. If I don't connect to BLE at all and never pair once and connect my device, the local app notifications slide in without problem letting me know that the iBeacon didEnterRegion and didExitRegion methods are being fired without trouble.
What am I doing wrong here?
I figured out this answer! I was sort of on the right path... It's not a great idea to try and disconnect from BT pairing in order to try to get iBeacon delegate methods to fire. It causes a lot of weird dirty code, tightly coupled things that shouldn't be and worse... the dreaded spaghetti code.
Instead my solution was to build a board with 2 Bluetooth chips in it. One as a dedicated iBeacon chip and the other as a permanent connected/paired/auth and bonded chip. This way there does not need to be any timed connection and disconnection events to be monitored (or worse... resolved race conditions). Waiting for a device to disconnect in iOS is not a true disconnect, it is instead when the iOS system thinks it's disconnected (in the phone's side of things). The things going on inside of the peripheral system paint a very different picture...
This 2 chip approach made life so much easier on the development side because now anytime you need the application to wake up to handle something, you can power cycle the iBeacon device and receive the appropriate event.
Side note: When using iBeacon the didEnterRegion method fires almost instantly where as the didExitRegion can take 30 or more seconds sometimes to fire. Therefore if you need immediate beacon detection resolution you should try to make sure the iBeacon is being powered on and not off for this... if even possible.
I am writing an iOS application which will communicate to a device using Bluetooth Low Energy (BLE).
When my connected device is out of range, my application is getting disconnect event.
But I am not getting any connect event when the device comes back to the range.
Please suggest any approach to detect when the device comes back to the range.
when you get the event that the device is no reachable anymore, you can launch a method which continuously checks if the device is still not reachable.
For example: while(isConnected==false)...
You say that you get a notification if the device disconnects, so you can use that event to launch such a method
When you receive the disconnect event, just restart the scan function:scanForPeripheralsWithServices or you can setup the scan mode to accept duplicate key by [_manager scanForPeripheralsWithServices:self.targetDeviceServiceIDs options:#{CBCentralManagerScanOptionAllowDuplicatesKey:#YES}]. which means the same device would be discovered for many time until you stop scanning.
Just reconnect in your disconnect method if the connection times out. There's no need to start a scan. It will automatically try to reconnect until it gets in range.
When your device get disconnected or goto out of range of Bluetooth then you don't need to scan for Peripheral devices because it already scanned for the BLE devices.
Call function [centralObj connectPeripheral:peripheral options:nil]; into didDisconnectPeripheral delegate method when BLE device disconnected.
I am creating a core bluetooth application and connecting to a peripheral device, is there a way for the peripheral to reject which centrals may connect to it? What if a random person scanned and found my peripheral devices broadcasted UUID and then broadcasted that UUID and tried to connect to it, how would I prevent this?
No, the iOS peripheral cannot prohibit centrals from connecting to it. However it has some tricks to disable the connection. When a dynamic characteristic is read:
return an error instead of the value of the characteristic,
don't respond to the request. This will cause the connection to stall and then break up after about 30 seconds.
Think of the advertisement as a real advertisement in the media. As many can see it as want. This is the same for iBeacons. You shouldn't rely any security on being hidden. (Wifi SSID broadcasting can be turned off but if your hotspot is not encrypted and authenticated, people with find you.)
The CBCentralManager retrieveConnectedPeripherals method says it gets "the list of the peripherals currently connected to the system." The definition of system is a bit ambiguous here.
Does this mean I get a list of peripherals connected to my app, or a list of peripherals connected to any app?
If I can get peripherals connected to another app, does this also mean multiple apps can connect to the same peripheral?
Can this only happen if the app is in the foreground, or do I need to allow for the possibility that a background app is sending commands to a peripheral I think my app owns?
BLE 4.0 enabled devices are usually connected with CBCentralManager unboundly. What is bounded and unbounded connection, you can know from this link.
One BLE 4.0 enabled device can be connected with only one master device thus enhancing secured connectivity. You should follow this link.
Whether in foreground of background, if the connection exists, the BLE slave device won't get connected with another app or device.