Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

iOS 26 Bluetooth disconnect issues

I have discovered a serious issue with Bluetooth connectivity on iOS 26.

My device use nrf52832 and sdk15.3, it consistently disconnects just a few seconds after a successful connection, then automatically reconnects in a continuous loop.

By using a Bluetooth packet sniffer and printing Bluetooth event logs, I found that iOS 26 sends a command to update connection parameters

" Control Opcode: LL_CONNECTION_UPDATE_IND" to Bluetooth slave devices (especially HID devices) every 120ms.

Moreover, the connection parameters it requests are also quite extreme.

The Bluetooth stack of the slave device cannot handle such a high frequency of update requests, ultimately leading to disconnection. Bluetooth stack shows a disconnection error code of 0x28, which corresponds to "Instant Passed."

I will attach my packet sniffer log images. I even suspect this is a very simple and stupid bug—the apple programmer mistakenly placed the Bluetooth parameter update procedure in the Bluetooth central callback event, causing a dead loop. The correct approach should be to request updates by a timer.

Our users are urging me to update the firmware to be compatible with iOS 26 every day. However, after trying some methods, I found that the problem could not be solved at all. Apple support also did not reply to my messages. Now I have no idea how to deal with this problem. Maybe someone in the community has encountered the same problem and solved it?

Parents
  • Can you please upload the entire sniffer trace (.pcapng file)? Screenshots doesn't say very much. 

    Do you observe the issue only using the combination of iOS26 and SDK 15.3.0 and the corresponding SoftDevice? 

    Best regards,

    Edvin

  • iOS26.pcapng

    Yes,this problem only occurs on iOS 26 and not on Android or earlier iOS versions.

    Also, I copied my log and related code for you to take a look.

    00> <info> app: Connection with link 0x1 established.
    00>
    00> <info> app: periph_link_cnt = 1
    00>
    00> <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 1, procedure: Encryption
    00>
    00> <info> app: Role:PERIPH, Data length set to 251
    00>
    00> <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Role:PERIPH, MTU set to 247
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Role:PERIPH, Data length set to 130
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Connection 0x1 has been disconnected. Reason: 0x28
    00>
    00> <info> app: periph_link_cnt = 0

    static void ble_peripheral_evt_handler(ble_evt_t const * p_ble_evt)
    {

    case BLE_GAP_EVT_DISCONNECTED:
    {

    NRF_LOG_INFO("Connection 0x%x has been disconnected. Reason: 0x%X",
    p_gap_evt->conn_handle,
    p_gap_evt->params.disconnected.reason);
    NRF_LOG_INFO("periph_link_cnt = %x", periph_link_cnt);

    }

    case BLE_GAP_EVT_CONN_PARAM_UPDATE:
    {
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_conn_params_t const * cur = &p_gap_evt->params.conn_param_update.conn_params;

    NRF_LOG_INFO("Conn params UPDATED: min=%u, max=%u, latency=%u, timeout=%u",
    cur->min_conn_interval, cur->max_conn_interval,
    cur->slave_latency, cur->conn_sup_timeout);
    }break;

    }

Reply
  • iOS26.pcapng

    Yes,this problem only occurs on iOS 26 and not on Android or earlier iOS versions.

    Also, I copied my log and related code for you to take a look.

    00> <info> app: Connection with link 0x1 established.
    00>
    00> <info> app: periph_link_cnt = 1
    00>
    00> <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 1, procedure: Encryption
    00>
    00> <info> app: Role:PERIPH, Data length set to 251
    00>
    00> <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Role:PERIPH, MTU set to 247
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Role:PERIPH, Data length set to 130
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=6, max=6, latency=0, timeout=200
    00>
    00> <info> app: Conn params UPDATED: min=12, max=12, latency=0, timeout=200
    00>
    00> <info> app: Connection 0x1 has been disconnected. Reason: 0x28
    00>
    00> <info> app: periph_link_cnt = 0

    static void ble_peripheral_evt_handler(ble_evt_t const * p_ble_evt)
    {

    case BLE_GAP_EVT_DISCONNECTED:
    {

    NRF_LOG_INFO("Connection 0x%x has been disconnected. Reason: 0x%X",
    p_gap_evt->conn_handle,
    p_gap_evt->params.disconnected.reason);
    NRF_LOG_INFO("periph_link_cnt = %x", periph_link_cnt);

    }

    case BLE_GAP_EVT_CONN_PARAM_UPDATE:
    {
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_conn_params_t const * cur = &p_gap_evt->params.conn_param_update.conn_params;

    NRF_LOG_INFO("Conn params UPDATED: min=%u, max=%u, latency=%u, timeout=%u",
    cur->min_conn_interval, cur->max_conn_interval,
    cur->slave_latency, cur->conn_sup_timeout);
    }break;

    }

Children
No Data
Related