This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Disconnected: 0 BLEHci.remote_user_terminated_connection [using pc_ble_driver_py]

Hello,

I am using the nordic nRF52840-DK and trying to connect to a nRF52840-Dongle and sending/receiving data to custom services and characteristics using pc_ble_driver_py. I modified the heart rate collector.

But the problem is that when I am connected to the Dongle the connection last 25 to 30 secondes and I receive a message : "Disconnected: 0 BLEHci.remote_user_terminated_connection" and the error message is : "line 477, in write_req attr_handle = self.db_conns[conn_handle].get_char_value_handle(uuid) KeyError: 0". However, when I use the nRF connect mobile/PC version I don't have this problem so I think it is a problem with my code. I check it out if there is some time out equal to like 25_30 secondes but I didn't find any solution.

Could someone help me please to find some solution.

Thanks in advance.

Cordially

Joe

Parents
  • Disconnected: 0 BLEHci.remote_user_terminated_connectio

    This means that  sd_ble_gap_disconnect() was called on the peer, with the reason BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION. If you can debug your peer you should be able to find where this is called.

    Kenneth

  • Hello,

    I edited the function connect() and I added a tag = 1 = CFG_TAG (the macro in the line number 33), I don't have anymore the problem BLEHci.remote_user_terminated_connection neither the errors.

    However, after like 250~253 secondes the connection will stop and I receive the message below :

    ---> Disconnected: 0 BLEHci.conn_interval_unacceptable

    Does anyone have any solution?

    Thanks in advance.

    Joe

  • Again, it should be possible to find where you are calling sd_ble_gap_disconnect() in your project, you can search for it in your project. I would assume it called in ble_conn_params.c, where you can find sd_ble_gap_disconnect(conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);.

    Typically setting cp_init.disconnect_on_fail             = false; when calling ble_conn_params_init() in main.c can remedy this.

    Kenneth

  • Hello,

    I misunderstood previous messages, I guess when you told me to check the sd_ble_gap_disconnect you meant on the C embedded code of the nRF device. I will double check that with the engineer who developped the embedded code.
    We also tried MIN_CONNECTION_INTERVAL and MAX_CONNECTION_INTERVAL timing modification (400ms and 650ms) as mentioned in https://devzone.nordicsemi.com/f/nordic-q-a/51542/pca10059-pca10056-pc-ble-driver-py-hrcollector-example , but we still have the disconnection issue after about 250s.

    However, the nRF firmware works well with our smartphone application and also with nRF connect on Android, iOS and windows.
    I also tried Bleak library with python that uses the PC bluetooth LE <Microsoft Bluetooth LE Enumerator> from intel(R) wireless Bluetooth(R), and it worked well.
    However using the nRF52840-DK with pc-ble-driver-py or blatann which is based on pc-ble-driver-py, I still face the disconnecting problem.

    So it seems more probable that the issue come from the BLE connection function in the python code and not from the nRF firmware itself.
    PS---> I will leave a code in attachements.
    To run the code you have to modify:
    • the mac adress at the line 26 respecting the spécific format as showed in the comment. To get the mac adress you can use the nrf connect BLE application.
    • the serial communication port at the line 110

    from time import sleep
    from queue import Queue, Empty
    from pc_ble_driver_py.observers import *
    
    global config, BLEDriver, BLEAdvData, BLEEvtID, BLEAdapter, BLEEnableParams, BLEGapTimeoutSrc, BLEUUID, BLEUUIDBase, BLEConfigCommon, BLEConfig, BLEConfigConnGatt, BLEGapScanParams
    from pc_ble_driver_py import config
    
    config.__conn_ic_id__ = "NRF52"
    
    from pc_ble_driver_py.ble_driver import (
        BLEDriver,
        BLEAdvData,
        BLEEvtID,
        BLEEnableParams,
        BLEGapTimeoutSrc,
        BLEUUID,
        BLEUUIDBase,
        BLEGapScanParams,
        BLEConfigCommon,
        BLEConfig,
        BLEConfigConnGatt,
    )
    # noinspection PyUnresolvedReferences
    from pc_ble_driver_py.ble_adapter import BLEAdapter
    
    TARGET_PEER_ADDR = [111, 222, 333, 444, 555, 666]  # <-- here you put your target address in this format
    CONNECTIONS = 1
    CFG_TAG = 1
    nrf_sd_ble_api_ver = config.sd_api_ver_get()
    
    
    class HR(BLEDriverObserver, BLEAdapterObserver):
    
        def __init__(self, adapter):
            super(HR, self).__init__()
            self.adapter = adapter
            self.conn_q = Queue()
            self.adapter.observer_register(self)
            self.adapter.driver.observer_register(self)
            self.adapter.default_mtu = 250
    
        def open(self):
            self.adapter.driver.open()
            gatt_cfg = BLEConfigConnGatt()
            gatt_cfg.att_mtu = self.adapter.default_mtu
            gatt_cfg.tag = CFG_TAG
            self.adapter.driver.ble_cfg_set(BLEConfig.conn_gatt, gatt_cfg)
            self.adapter.driver.ble_enable()
    
        def close(self):
            self.adapter.driver.close()
    
        def connect_and_discover(self):
            scan_duration = 180
            params = BLEGapScanParams(interval_ms=200, window_ms=150, timeout_s=scan_duration)
    
            self.adapter.driver.ble_gap_scan_start(scan_params=params)
    
            try:
                new_conn = self.conn_q.get(timeout=scan_duration)
                self.adapter.service_discovery(new_conn)
    
                return new_conn
            except Empty:
                return None
    
        def on_gap_evt_connected(self, ble_driver, conn_handle, peer_addr, role, conn_params):
            print("New connection: {}".format(conn_handle))
            self.conn_q.put(conn_handle)
    
        def on_gap_evt_disconnected(self, ble_driver, conn_handle, reason):
            print("Disconnected: {} {}".format(conn_handle, reason))
    
        def on_gap_evt_adv_report(self, ble_driver, conn_handle, peer_addr, rssi, adv_type, adv_data):
            if BLEAdvData.Types.complete_local_name in adv_data.records:
                dev_name_list = adv_data.records[BLEAdvData.Types.complete_local_name]
    
            elif BLEAdvData.Types.short_local_name in adv_data.records:
                dev_name_list = adv_data.records[BLEAdvData.Types.short_local_name]
    
            else:
                return
            dev_name = "".join(chr(e) for e in dev_name_list)
            address_string = ":".join("{0:02X}".format(b) for b in peer_addr.addr)
            if peer_addr.addr == TARGET_PEER_ADDR:
                self.adapter.connect(peer_addr, tag=1)
    
        def on_notification(self, ble_adapter, conn_handle, uuid, data):
            if len(data) > 32:
                data = "({}...)".format(data[0:10])
            print("Connection: {}, {} = {}".format(conn_handle, uuid, data))
    
    
    def main(selected_serial_port):
        print("Serial port used: {}".format(selected_serial_port))
        driver = BLEDriver(serial_port=selected_serial_port, auto_flash=False, baud_rate=1000000, log_severity_level="info")
        adapter = BLEAdapter(driver)
        collector = HR(adapter)
        collector.open()
        conn = collector.connect_and_discover()
    
        if conn is not None:
            while True:
                pass
    
        collector.close()
    
    
    if __name__ == "__main__":
        main("COM9")  # <-- here you put your serial communication "COM" number
    
  • I can only assume that the dongle (operating in the central role) will be receiving an BLE_GAP_EVT_CONN_PARAM_UPDATE request from the peer device (operating in peripheral device). See here for an example:

    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v6.1.1/group___b_l_e___g_a_p___c_e_n_t_r_a_l___c_p_u___m_s_c.html

    If this event is unhandled or not accepted, it is likely that the peer device may disconnect based on the configuration set during ble_conn_params_init().

  • Hello,

    I tested the blinky example in the SDK on the dongle :

    • nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_blinky\hex\pca10059\hex\ble_app_blinky_pca10059_s140.hex

    I can send data to the dongle from nrfconnect PC app, and it still connected to it as long as you don’t disconnect it. However, when using the python library, I will receive the same error and the connection will lost.

    Could you please try to run the last python script modifying the adress mac corresponding to the dongle with the blinky firmware and the serial communication port corresponding to the nrf52840-DK board.

    thanks

    Joe

Reply
  • Hello,

    I tested the blinky example in the SDK on the dongle :

    • nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_blinky\hex\pca10059\hex\ble_app_blinky_pca10059_s140.hex

    I can send data to the dongle from nrfconnect PC app, and it still connected to it as long as you don’t disconnect it. However, when using the python library, I will receive the same error and the connection will lost.

    Could you please try to run the last python script modifying the adress mac corresponding to the dongle with the blinky firmware and the serial communication port corresponding to the nrf52840-DK board.

    thanks

    Joe

Children
  • We check with the enginneer who developped the firmware in debug mode, it appears the dongle get a BLE_GAP_EVT_DISCONNECTED when I get the error
    Disconnected: 0 BLEHci.conn_interval_unacceptable from python.
    Then we added a break point in this function
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
    uint32_t err_code;
    if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
    {
    err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
    APP_ERROR_CHECK(err_code);
    }
    }
    and as you previously mentionned
    sd_ble_gap_disconnect(conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE); is called.
    We check cp_init.disconnect_on_fail, it is already set "false"

    in fact we have this setting for cp_init:
    cp_init.p_conn_params = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail = false;
    cp_init.evt_handler = on_conn_params_evt;
    cp_init.error_handler = conn_params_error_handler;
    with
    #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000)
    #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000)
    #define MAX_CONN_PARAMS_UPDATE_COUNT 3
    #define BLE_GATT_HANDLE_INVALID 0x0000
  • we tried to add in the connect() function --> self.adapter.connect(peer_addr, conn_params=conn_params, tag=1) with conn_params = BLEGapConnParams(min_conn_interval_ms=125, max_conn_interval_ms=250, conn_sup_timeout_ms=4000, slave_latency=0)

    as it was in the dongle. But we still have the same error.

    Thanks

  • I need the sniffer log to help you further.

    Kenneth

  • Hello,

    I captured packets by sniffing blinky example on the dongle using wireshark. I send ON from master --> slave and then receiving the led state from slave --> master and when i receive Disconnected: 0 BLEHci.conn_interval_unacceptable using python, I receive in wireshark Control Opcode: LL_TERMINATE_IND (0x02) from slave --> master. I will put some screen captures in the first one you can see that it is normal I can send and receive and in the second one you will see that after some times I will receive the Control Opcode: LL_TERMINATE_IND.

    this is the first one

    first one

    this is the second one

    second one

    And the third one is when I double click on the error sniff.

    Thanks

  • Great, can you share the sniffer file (.pcapng) here?

    Kenneth

Related