Would it be possible to share your project or specify the steps to reproduce the issue? CyBle_GapAuthReq() is indeed the correct API to request for authentication and/or encryption.
I can't post the project as it is for a release product, but I can attach a pseudocode showing the steps I'm taking.
Given a specific input, wake up the unit from deep sleep, read some measurements, start the BLESS with CyBle_Start(stack_handler) (checking the return value for failure). Once the stack is up and running, scan for desired device, connect to it.
Then, wait until the other side sends a CYBLE_EVT_GAP_AUTH_REQ, and reply with CyBle_GapAuthReq().
Once encrypted, it exchanges data, then disconnects and turns off the BLE stack with CyBle_Stop()
Once the BLESS is off, wait until another user input to call CyBle_Start(stack_handler), and then repeat the same steps as before, but it proceeds to fail upon execution of the CyBle_GapAuthReq() function.
It could be that the other end of the connection is returning an error on the CyBle_GapAuthReq(), but since it is bonding correctly with the dongle upon connection and allowing the dongle to read/write etc, it seems like it is the CyBle_GapAuthReq() function that is failing somehow.
Is there a reason that you are completely turning off the stack? Normally this is not required, even if your goal is to stop all BLE activity. All you really need to do is the following:
- Disconnect if you are connected
- Stop advertising if you are currently advertising in any state (including broadcast/non-connectable)
- Stop scanning if you are currently scanning
At this point, the BLE stack will be effectively "off" and will not trigger any interrupts or consume power, but it is also ready to resume activity at any time.
I'm completely turning off the stack because I thought it would be consuming power/have the radio on while inactive. Should I be merely starting the stack on chip bootup, and then just putting it into deepsleep when not in use? So, you are saying that all physical hardware is only tied to: Active connections, Advertising, and Scanning? Turning off any of those three cases will have the radio completely off?
I guess I assumed the CyBle_Stop() function was for fully turning off the radio, while the low power modes were for leaving the radio on but reducing power during use. I will modify it to not turn the whole stack on/off and see if that fixes it.
Re-architecting the code to only cally CyBle_Start() once at bootup seems to have fixed the problem. Thanks for the help jrow and yssu!
Actually, after testing it, I'm running into the same HCI error :(
I'm only calling cyble_start() on bootup, and I never call cyble_stop(). Should I be calling cyble_stop() on a software reset? Is there some deeper meaning to the CYBLE_HCI_HOST_REJECTED_LIMITED error?
Could it be the other side of the connection not having enough resources? Or is it only the local side that sends the error?
The error event seems to be in response to connecting to a remote device after calling CyBleGapAuthReq() to pair/encrypt the connection, but based on what I'm seeing with the USB dongle, I need to send the request in order to connect?
Does it matter if the other device has sent a request for pairing to the "central" device before the central device calls the CyBleGapAuthReq()?
Based on my understanding of the spec, the GATT server typically should not be responsible for initiating the encryption process. You definitely don't want both sides attempting to encrypt at the same time, in any case. Rather, the client should initiate the encryption/bonding process after receiving a GATT error response indicating that the current link state is not secure enough for the action it just tried to do. The recommended flow goes like this:
- Unencrypted client tries to read data from an auth-required characteristic.
- Server responds with "insufficient authentication" GATT error
- Client encrypts link (new bond is created here if not previously bonded)
- Upon completion, client retries GATT operation
Practically, one common approach I have seen is for the server to include an auth-required characteristic, and the client-side mobile app intentionally attempts to use it first thing after connecting. That ensures that the correct order of operations takes place every time, and the server/peripheral is never responsible for initiating encryption.
I guess that explains why I was getting an error then; I setup both sides to do encryption as soon as the connection was up. The documentation listed the server-side as being a "request for pairing" sent to the client, but there must be a race condition going on there then.
If you know that you will need encryption/pairing with the server, wouldn't it be valid to encrypt/pair as soon as you are connected, rather than waiting until an error? It seems like the only difference would be switching the handling of the pairing process between internal logic/timing on the main app code, and error-handling in the callback stack.
Thanks for the help, I'll see if I can clean it up so that I stop getting errors :)