BLE failures with EIO

I'm developing a BLE application using several connections, and of course I'm advertising and scanning to establish those connections. I have up to 5 connections at a time and running both peripheral and central roles.

Occasionally I get an error when trying to do a BLE operation and it's not clear to me what the error means for how I should respond. In particular I sometimes get -EIO when calling bt_le_ext_adv_start() or bt_conn_disconnect(). A cursory look through the code in these functions doesn't show an obvious reason why EIO occurs, except that it may be caused by an error when sending an HCI command to the controller in bt_hci_cmd_send_sync(). Looking at the logs, I do sometimes see a warning like "bt_hci_core: opcode 0x200e status 0x0c" which is indeed generated in bt_hci_cmd_send_sync(). Since the EIO error only occurs occasionally I suspect it may be occurring due to a timing window where the host and controller are out of sync, or some other transient condition. In some cases retrying the operation later works eventually, sometimes not (advertising seems to often fail many times in a row and then succeed; disconnecting failures seem to never succeed with retries).

At the end of the day I just want my application to robustly handle error conditions like this. But, with the error code EIO I'm not sure how to respond. If it's dependent on the specific opcode/status code, the application doesn't have access to this information (only EIO). Can you give me any insight into what I should do in situations like this? Is there any way for the application to know more specific error codes so it can respond appropriately?

Details: I am using NCS 2.4.1 on the nRF5340 with the net core running the soft device controller. I think these are the relevant parts of my project configuration.

App core:

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y

CONFIG_BT_MAX_CONN=5

CONFIG_BT_EXT_ADV=y
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2

CONFIG_BT_GATT_DM=y

CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_ACL_TX_COUNT=20
CONFIG_BT_BUF_ACL_RX_SIZE=251

CONFIG_BT_FILTER_ACCEPT_LIST=y
CONFIG_BT_USER_PHY_UPDATE=y
CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_SMP=y
CONFIG_BT_DEVICE_NAME="ABC"

CONFIG_BT_ATT_PREPARE_COUNT=2
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n

CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y

CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=y
CONFIG_BT_SCAN_UUID_CNT=1

Net core:

CONFIG_BT_MAX_CONN=5

CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_ACL_TX_COUNT=20
CONFIG_BT_BUF_ACL_RX_SIZE=251

CONFIG_BT_CTLR=y
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=255
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_SET=2
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_CTLR_PHY_2M=y
CONFIG_BT_CTLR_PHY_CODED=y
CONFIG_BT_CTLR_RX_BUFFERS=10
CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y

CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=1

  • Hi Steve,

    I have been assigned this ticket but I could not look at it in depth.

    I will work on it on Monday and I will come back to you once I have more information to share.

    BR, Naeem

  • Hello Steve,

    Thank you for your patience.

    The function bt_le_ext_adv_start() calls the bt_le_adv_set_enable_ext() function, which in turn calls the bt_hci_cmd_send_sync() function, and that is returning the -EOI.

    The function bt_hci_cmd_send_sync() is used for sending a HCI command synchronously. The function will block until a Command Status or a Command Complete event is returned. If either of these have a non-zero status, which happens to be the case you are experiencing, then the function returns a negative error code.


    As per the code (in hci_core.c), the function will return 0 if successful, or -ENOBUS (if buffer creation was unsuccessful), or -ECONNREFUSED (if status=0x09), or -EOI for all other values of the status. So yes, I agree with you that -EOI does not provide much information.


    However, the status which in your case is 0x0c means the HCI Error is that the Command is DisAllowed (BT_HCI_ERR_CMD_DISALLOWED). As per bluetooth core specification, the Command Disallowed error code indicates that the command requested cannot be executed because the Controller is in a state where it cannot process this command at this time.

    Regards, 
    Naeem

  • Thanks Naeem, that is encouraging as it matches what I could learn from reading the code.

    I'm not sure where to go from here, though. Why might the controller not be able to process the command? From my perspective I have a valid connection handle that I want to disconnect, so I'm not sure what state the controller might be in that would disallow this. In my experience retrying the command doesn't help - I continue to get the same error. I'm not sure what else to do, though. Is there a way for me to find out what the root cause might be? What would you recommend I do to continue investigating this?

  • I am not sure, but could it be related to timings, or number of connections?

    What is the parameter you are passing when calling those function?

    can you change and try again ... 

    also, can you put some delay before you call the function.

    these are just for testing purposes.

    and when you try to disconnect, you make sure that connection exists.

    what if there is no connection and you are calling to disconnect?

Related