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.
Related
So I am building an IoT device and now I am working on battery optimizations. I am able to tell the device to connect to a central it has bonded to. This works(ish). You can observe the device connecting in bluetooth settings, but about 5 seconds later it disconnects. I would assume that since there is nothing happening and nothing asking for it, it drops the connection. I also assume that this is allowed for ANCS. What I want to know is can it be used for anything else? I would like to be able to shut off the device, not have to scan constantly in app, and have the system notify my central manager that the device has connected later (when a user wakes it up.
I know I can call
[_manager retrievePeripheralsWithIdentifiers:identifiers];
to get devices I have connected to before, but I am not seeing a way to attach unconnected ones to the manager so that when they do connect in the background, the app knows about it. Anyone have a solution for this?
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.
I've noticed that when you disconnect for a bluetooth device in an application the iOS device will continue to hold that connection for around 10 seconds. I've attempted to get around this by writing to a characteristic that causes the bluetooth module to cancel the connection with the iOS device instead but that isn't working (mostly because I changed the module and the iOS doesn't see the change because I assume the device is cached somewhere). Is there a way to make it disconnect instantly in code? I am using the swift command
manager.cancelPeripheralConnection(peripheral) currently.
Unfortunately, there isn't. The only way to tell the system to disconnect a peripheral is via the cancelPeripheralConnection method that you are already using. Yet, if you call this method it doesn't necessarily mean that the peripheral will be disconnect.
Background
On iOS the whole BLE connection management is maintained by the operating system. That means that no single application "owns" a connection. All BLE functionality is multiplexed to allow more than one application to gain access to centrals and peripherals.
For example, if you have installed a fitness application that tracks data from your heart rate sensor in the background then you can also "connect" to the heart rate sensor in your app but you will be unable to trigger a real disconnect as long as the fitness app maintains a connection.
The disconnect delay you have noticed is basically an optimization of the operating system. If no application holds a connection to the peripheral anymore it will wait for some time (to avoid unnecessary connect/disconnect cycles) and then trigger the disconnect on the bluetooth chip.
Hope that helps.
In iOS when you call the CBCentralManager method cancelPeripheralConnection(CBPeripheral), it does not always immediately terminate the connection. As Apple's documentation states:
Because other apps may still have a connection to the peripheral, canceling
a local connection does not guarantee that the underlying physical link is
immediately disconnected. From the app’s perspective, however, the
peripheral is considered disconnected, and the central manager object calls
the centralManager:didDisconnectPeripheral:error: method of its delegate
object.
If you have a need to immediately terminate a connection programmatically, say to free up the peripheral to be connected from another central device or to reset one's own security layer, then you need to follow the procedure described in the following StackOverflow thread:
iOS 6 - Bluetooth LE disconnect
which is for the app to send your own proprietary command to the peripheral that tells the peripheral to disconnect through normal means (e.g. "GAPRole_TerminateConnection" or "GAP_TerminateLinkReq" or "LL_Disconnect" or "HCI_Disconnect[_*]" with reason HCI_DISCONNECT_REMOTE_USER_TERM). This always works and is not delayed by the connection supervision timeout because it is a formal disconnection notifying the central device (i.e. iOS). The supervision timeout (up to 6 seconds in iOS; on Android the default is 20 seconds) only comes into play if the disconnection is unplanned as with going out of range or if the peripheral does a disconnect without notifying the remote device as with "LL_EXT_DisconnectImmed" (only available in some BLE peripheral implementations).
My application related to bluetooth communication with the peripheral device.Every functionality is working fine right from discovering to connecting .While coming to disconnecting the peripheral from the application i have written code like this
-(void) disconnect
{
if (_selectedPeripheral != nil &&
_selectedPeripheral.state != CBPeripheralStateDisconnected)
{
NSLog(#"Peripheral disconnecting");
[_centralManager cancelPeripheralConnection:_selectedPeripheral];
_selectedPeripheral = nil;
}
}
When i click button this above method is calling and app showing that peripheral is disconnected and when i came out of the application and look into settings /bluetooth/ .Peripheral is showing connected.How to stop connection the peripheral in the device level i.e in the settings .Please help me with the proper solution.
You are unable to guarantee a system level disconnect from the peripheral.
This is a link directly from the CBCentralManager documentation:
cancelPeripheralConnection:
Discussion
This method is nonblocking, and any CBPeripheral class
commands that are still pending to peripheral may or may not complete.
Because other apps may still have a connection to the peripheral,
canceling a local connection does not guarantee that the underlying
physical link is immediately disconnected. From the app’s perspective,
however, the peripheral is considered disconnected, and the central
manager object calls the centralManager:didDisconnectPeripheral:error:
method of its delegate object.
In my experience the physical link is disconnected quickly if you are the only application using the peripheral, but if you potentially are not as Apple clearly states there is a potential for other applications to be maintaining a persisted connection which would cause the physical link to not disconnect even though it is stating to you it has.
We were facing the same issue but we managed to workaround this nasty bug (or API design flaw) by using
Objective C
[peripheral writeValue:x forCharacteristic:y type:CBCharacteristicWriteWithResponse];
Swift
peripheral.writeValue(x, for: y, type: .withResponse)
It's strange that iOS doesn't cancel the physical connection to the peripheral we implemented in the peripheral to perform the disconnect, so we send a string indicating a disconnection should happen.
We used
Objective C
[peripheral writeValue:x forCharacteristic:y type:CBCharacteristicWriteWithoutResponse];
Swift
peripheral.writeValue(x, for: y, type: .withResponse)
and the peripheral disconnects as expected.
Hope this helps anyone facing the same issue by this CoreBluetooth API flaw.
x is the specific cmd supported in your peripheral device (i.e Firmware)
y is the specific characteristic you want to send the value
I know this is an old thread, but I figured I'd add a potential solution here for others.
What you could do is issue a command that causes the peripheral to reboot, resetting the Bluetooth connection. If your device has such a command that you can issue through Bluetooth, you're in luck, otherwise, you'll need access to the firmware for the peripheral in order to add a new command that does this. I'm not a firmware guy, so I can't tell you what exactly you need to do; all I know is the device I'm working with has such a command (it is a proprietary command specifically for our device, not part of the Bluetooth protocol) and that allowed the disconnect to be guaranteed as long as I issue it before calling cancelPeripheralConnection.
I am getting unexpected behavior. I am making a simple wrapper on Corebluetooth and made 2 apps: one acts as client and other as server.
On the server end, whenever I am updating characteristic value through [updateValue: forCharacteristic: onSubscribedCentral] I am getting response as 0. According to Apple documentation, It will return YES if the update could be sent, or NO if the underlying transmit queue is full.I googled for this error and found that this can be handled by sending the data again in peripheralManagerIsReadyToUpdateSubscribers: method. This is working fine.
Issue comes in client end.
After connecting to device, and reading values successfully, my peripheral gets disconnected with error : The specified device has disconnected from us. This happens in spite of the fact my server is continuously sending values. My problem is somewhat similar to
Peripheral transmit queue issue
but in my case sometime peripheral remain connected and value is updated on client side. But most of time peripheral disconnects.
I have googled a lot for the solution even tried few advices given at:
CoreBluetooth repeatedly disconnecting. But of no use.