Re: Invalid peripherals returned by CBCentralManager after reconnect?
Re: Invalid peripherals returned by CBCentralManager after reconnect?
- Subject: Re: Invalid peripherals returned by CBCentralManager after reconnect?
- From: Etan Kissling <email@hidden>
- Date: Wed, 17 Apr 2013 20:15:27 +0000
- Thread-topic: Invalid peripherals returned by CBCentralManager after reconnect?
1. Call cancelPeripheralConnection from your iPhone
2. On your peripheral, restart advertising when you received a TERMINATE_IND
3. On your iPhone, restart scanning. You will only discover the peripheral again,
when the TERMINATE_IND went through
4. When you discovered the peripheral again, connect to it.
For paranoia, you could also check "retrieveConnectedPeripherals" before connecting
to ensure that iOS does not report the peripheral as "connected to the system" anymore
prior to connect.
Etan
On 17.04.2013, at 22:12, Anthony Stevens <email@hidden>
wrote:
> Thanks again for the detailed responses, Etan.
>
> How do I perform Case 2? I'll run Case 3 as well and report back.
>
>
> On Apr 17, 2013, at 12:11 PM, Etan Kissling <email@hidden> wrote:
>
>> Anthony,
>>
>> this at least gives you a "valid" workaround :-)
>> => Periodic screen-shotting and pixel-testing until the B-icon is white!
>>
>>
>> At topic: maybe that's only when disconnecting from the peripheral side.
>> As pointed out before, a next step would be to analyze behavior when
>> disconnecting form the iPhone (with 10s delay or so), and if that works,
>> to evaluate what happens when you simply move the peripheral out of
>> link range.
>>
>> These are three different cases:
>> - case 1 [bugged]: remote disconnect by sending TERMINATE_IND
>> - case 2: iphone disconnect by sending TERMINATE_IND
>> - case 3: disconnect by simply not replying anymore.
>>
>> For testing, it may be easier to disable the antenna on your peripheral.
>> Otherwise, have a nice run back and forth :-) Or does your isolation chamber
>> also supports different rooms that can be locked down independently to test
>> out-of-range behavior?
>>
>>
>>
>> Regarding remote disconnecting:
>>
>> If it turns out that it is not safe to remotely disconnect, let me point out that it was
>> previously discussed on this mailing list and that it is discouraged, as a different
>> app B may still be connected to the peripheral. You cannot know in app A if app B
>> is there, accessing the peripheral, and if you initiate a remote disconnect, you kick
>> app B out of the connection, as both apps are multiplexed over the same physical channel.
>>
>> This is also a violation of the Bluetooth Core Spec, as a peripheral must not serve
>> multiple connections at a time. Maybe it's allowed in a loose interpretation where
>> you consider multiple logical connections multiplexed over a single physical connection
>> as ok, but it's definitely making disconnection under iOS harder than it should be.
>>
>> Etan
>>
>>
>> On 17.04.2013, at 20:57, Anthony Stevens <email@hidden>
>> wrote:
>>
>>>
>>> Etan,
>>>
>>> Good question about the iOS bt icon. When a valid connection is made, the bluetooth icon is active/white when CBCentralManager replies on didConnectPeripheral. When a invalid connection is made (will rapidly timeout and disconnect), the bluetooth icon is inactive/gray when CBCentralManager replies on didConnectPeripheral.
>>>
>>> This seems like a white flag that something is odd on the iOS bluetooth stack side.
>>>
>>>
>>> On Apr 17, 2013, at 11:12 AM, Etan Kissling <email@hidden> wrote:
>>>
>>>> Anthony,
>>>>
>>>> sorry for the spamming, but got one more idea:
>>>> What happens when you use a new CBCentralManager for every test cycle? Maybe that's a
>>>> way hardcore enough to reset the remnants of the previous connection completely.
>>>>
>>>> The documentation only states that CBPeripheralManager should be used as a singleton -
>>>> for CBCentralManager there's no similar entry. Note however that CBPeripherals found with
>>>> one CentralManager cannot be used with a different one that found them.
>>>>
>>>> Etan
>>>>
>>>>
>>>> On 17.04.2013, at 20:03, Etan Kissling <email@hidden>
>>>> wrote:
>>>>
>>>>> Anthony,
>>>>>
>>>>> one more idea: iOS changes the Bluetooth address regularly to increase privacy. Could it be
>>>>> that the connection fails when the address is changing while your request is pending? / Is the
>>>>> first request that succeeds after a failed request coming from a different BD_ADDR than the
>>>>> requests before that succeeded?
>>>>>
>>>>> And there were some issues mainly on iOS 5 with the Bluetooth stack resetting from time to time
>>>>> most often when under heavy strain. Does your centralState always remain at PoweredOn?
>>>>>
>>>>> Etan
>>>>>
>>>>>
>>>>>
>>>>> On 17.04.2013, at 19:55, Etan Kissling <email@hidden>
>>>>> wrote:
>>>>>
>>>>>> Anthony,
>>>>>>
>>>>>> yep, initiating a remote disconnect is a common practice since iOS 5 and I also used it in some
>>>>>> of our projects.
>>>>>>
>>>>>> iOS displays the white B icon in the status bar when a connection is active. In the cases
>>>>>> where your reconnection problem occurs, is it still visible? Maybe you could capture
>>>>>> a screenshot when the error is thrown…
>>>>>>
>>>>>> If the icon is still there, it could indicate that iOS still thinks that it is connected to the peripheral.
>>>>>> Maybe the remote disconnect doesn't get handled by all subsystems of the iOS stack properly,
>>>>>> although it's strange because your app at the top of the stack actually receives the didDisconnect
>>>>>> callback.
>>>>>>
>>>>>> Other than that, another attempt to isolate the bug would be to check if there are similar issues
>>>>>> when disconnecting from the iOS device instead of through remote disconnection (adding the small
>>>>>> delay after receiving the didDisconnect callback).
>>>>>>
>>>>>> One more thing to look at could be to check whether IsConnected is set to NO after the didDisconnect
>>>>>> callback occurs. And then checking if it erroneously stays at YES when the next connect call fails.
>>>>>>
>>>>>> And a small stupid-error check: Ensure that your peripheral is really retained properly while it is being
>>>>>> used. Bad things happen when it is not retained, but because most of your connection attempts work
>>>>>> correctly, I think that your code is fine.
>>>>>>
>>>>>>
>>>>>> Etan
>>>>>>
>>>>>>
>>>>>> On 17.04.2013, at 19:40, Anthony Stevens <email@hidden>
>>>>>> wrote:
>>>>>>
>>>>>>> Etan,
>>>>>>>
>>>>>>> I just ran a test with delay = 35 seconds and get the same timeout error within the first 5 connect-disconnect-reconnect cycles.
>>>>>>>
>>>>>>> To be clear though, we are disconnecting by writing a characteristic on the peripheral so that the peripheral disconnects the link. My understanding is that this should mitigate any lingering connection issue like you suggested where iOS terminates the logical link but keeps the physical link. I.e. the physical link was killed by the peripheral prior to CBCentralManager calling didDisconnectPeripheral .
>>>>>>>
>>>>>>> Also we see the TERMINATE_IND coming from the peripheral after we write the characteristic.
>>>>>>>
>>>>>>> I appreciate your help though and any additional guidance would be greatly appreciated.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Anthony
>>>>>>>
>>>>>>>
>>>>>>> On Apr 17, 2013, at 10:11 AM, Etan Kissling <email@hidden> wrote:
>>>>>>>
>>>>>>>> Anthony,
>>>>>>>>
>>>>>>>> when you disconnect with cancelPeripheralConnection, do you see an actual TERMINATE_IND in your sniffed traffic?
>>>>>>>>
>>>>>>>>
>>>>>>>> Etan
>>>>>>>>
>>>>>>>>
>>>>>>>> On 17.04.2013, at 19:09, Anthony Stevens <email@hidden>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Etan,
>>>>>>>>>
>>>>>>>>> I tried a 5 second then 15 second delay between disconnect-reconnect, but the timeout errors were still happening on iOS 6.1. This seemed more than enough time. I'm running a 35 second delay test right now and will report back.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Anthony
>>>>>>>>>
>>>>>>>>> On Apr 17, 2013, at 8:24 AM, Etan Kissling <email@hidden> wrote:
>>>>>>>>>
>>>>>>>>>> Anthony,
>>>>>>>>>>
>>>>>>>>>> iOS already gives you a didDisconnected confirmation when only the logical link between your app and the controller is disconnected. The physical link is only disconnected about 2-3 seconds after all apps disconnected logically on iOS 5/6.1 and after about 30 seconds on iOS 6.0 if I recall correctly.
>>>>>>>>>>
>>>>>>>>>> I think that if you reconnect too fast, the last disconnect request may still be pending in some driver code when the logical link is already reconnected, and that it kills the connection because it could not be aborted in time by the system.
>>>>>>>>>>
>>>>>>>>>> What happens if you add 5 sec delays after the didDisconnect callback before you reconnect again?
>>>>>>>>>>
>>>>>>>>>> Etan
>>>>>>>>>>
>>>>>>>>>> On 17.04.2013, at 16:26, "Anthony Stevens" <email@hidden> wrote:
>>>>>>>>>>
>>>>>>>>>>> We're developing an app using iOS's low energy bluetooth stack. The app connects with a peripheral device to periodically read data. All's great except for a persistent, yet random, immediate peripheral timeout on re-connect. This is the error detail from CBCentralManager at didDisconnectPeripheral.
>>>>>>>>>>>
>>>>>>>>>>>> Domain=CBErrorDomain
>>>>>>>>>>>> Code=6
>>>>>>>>>>>> NSLocalizedDescription=The connection has timed out unexpectedly
>>>>>>>>>>>
>>>>>>>>>>> Each disconnect happens as soon as we call discoverServices on the newly connected peripheral (which has [peripheral isConnected] == YES). When looking at the peripheral's logs, it shows it is not receiving a connection request from iOS over bluetooth. When placed in a bluetooth isolation chamber, our bluetooth sniffer sees no bluetooth connection request packets for these timed-out connections…implying that CBCentralManager is replying in didConnectPeripheral with a peripheral that cannot really be connected.
>>>>>>>>>>>
>>>>>>>>>>> We've written a test harness to reliably reproduce this issue. The harness establishes a connection, transmits/receives some data, explicitly writes a characteristic to have the peripheral terminate the connection, then attempts to reconnect. For every 100 connect-then-reconnects, an average 10 of these will experience a peripheral timeout on re-connect. After 2-3 timeout on re-connect attempts, a lasting connection is established and the harness proceeds with its cycling.
>>>>>>>>>>>
>>>>>>>>>>> Here are the steps followed by the test harness:
>>>>>>>>>>>
>>>>>>>>>>> 1. Scan for a peripheral.
>>>>>>>>>>> 2. Stop scan
>>>>>>>>>>> 3. Call [CBCentralManager connectPeripheral]
>>>>>>>>>>> 4. CBCentralManager replies on didConnectPeripheral.
>>>>>>>>>>> 5. Call discoverServices on peripheral
>>>>>>>>>>> 6. Read/write data to/from peripheral
>>>>>>>>>>> 7. Explicitly disconnect peripheral by writing a characteristic
>>>>>>>>>>> 8. CBCentralManager replies on didDisconnectPeripheral
>>>>>>>>>>>> CBErrorDomain Code=7
>>>>>>>>>>>> The specified device has disconnected from us
>>>>>>>>>>> 9. Perform a reconnect by returning to step 1
>>>>>>>>>>>
>>>>>>>>>>> Roughly 10% of the time when we perform the reconnect in step 9, we see the below happen 2-3 times before a successful reconnect
>>>>>>>>>>>
>>>>>>>>>>> 1-5 as above
>>>>>>>>>>> 6. CBCentralManager replies on didDisconnectPeripheral
>>>>>>>>>>>> Domain=CBErrorDomain
>>>>>>>>>>>> Code=6
>>>>>>>>>>>> NSLocalizedDescription=The connection has timed out unexpectedly
>>>>>>>>>>> 7. Perform a reconnect by returning to step 1
>>>>>>>>>>>
>>>>>>>>>>> We have also tried scanning just the first time during the harness testing and reusing the original peripheral. The results are the same. Our issue sounds suspiciously similar to the one posted by Maxim in February: http://lists.apple.com/archives/bluetooth-dev/2013/Feb/msg00090.html
>>>>>>>>>>>
>>>>>>>>>>> Any guidance would be greatly appreciated.
>>>>>>>>>>>
>>>>>>>>>>> Thank you,
>>>>>>>>>>> Anthony
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> Do not post admin requests to the list. They will be ignored.
>>>>>>>>>>> Bluetooth-dev mailing list (email@hidden)
>>>>>>>>>>> Help/Unsubscribe/Update your Subscription:
>>>>>>>>>>>
>>>>>>>>>>> This email sent to email@hidden
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> Do not post admin requests to the list. They will be ignored.
>>>>>> Bluetooth-dev mailing list (email@hidden)
>>>>>> Help/Unsubscribe/Update your Subscription:
>>>>>>
>>>>>> This email sent to email@hidden
>>>>>
>>>>> _______________________________________________
>>>>> Do not post admin requests to the list. They will be ignored.
>>>>> Bluetooth-dev mailing list (email@hidden)
>>>>> Help/Unsubscribe/Update your Subscription:
>>>>>
>>>>> This email sent to email@hidden
>>>>
>>>
>>
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Bluetooth-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden