pc-ble-driver-py How to use numerical comparison ?

Hi,

I know that pc-ble-driver-py is archived but as there is no real alternative to it, I'm still using this package...

I'm using BLE nRF52840 dongle to connect to a BLE target.

When using exemple "test_lesc_security.py", I'm able to connect to the target. But when I tried to perform bonding (with keyboard_display and lesc=True), the event 'on_gap_evt_passkey_display' is trigger so I can read the passkey but I didn't understand how to match it. (The BLE target automatically match the key on it's side)

While using nRF Connect Desktop, I have no issue with numerical comparison (and same settings used with adapter.driver.ble_gat_authenticate).

Does someone successfully perform numerical comparison with pc-ble-driver-py ?

Note: 

In pc_ble_driver_py/lib.nrf_ble_driver_sd_api_v5.py there is 'ble_gap_evt_passkey_display_t" with "match_request". Does this mean it's possible to match the numerical comparison ?

Best regards,

Antoine

  • Hi Susheel,

    Thank you for the details response.

    As I don't program that much on microcontrollers, it can take some times to perform the test with Bluetoth shell.

    From what I understand, at the event "on_gap_evt_passkey_display" I need to send back the passkey with "sd_ble_gap_auth_key_reply" as below ?

        def on_gap_evt_passkey_display(self, ble_driver, conn_handle, passkey): # Reached with IOCaps = keyboard_display/none/yesno
            self.logger.info("Central on_gap_evt_passkey_display: {}".format(passkey))
            ascii_passkey = ''.join(map(chr, passkey))
            self.logger.info(f"Central on_gap_evt_passekey_display (ASCII): {ascii_passkey}")
            passkeyQueue.put(passkey)
    
            # Send passkey as it has been printed on display
            pk = util.list_to_uint8_array(passkey)
            driver.sd_ble_gap_auth_key_reply(self.adapter.driver.rpc_adapter,conn_handle,driver.BLE_GAP_AUTH_KEY_TYPE_PASSKEY, pk.cast())

    Or should I add a parameter "match_request" in ble_driver.py (and observers.py) for on_gap_evt_passkey_display ?

    By any chance, do you have any exemple on that ?

    As nRF Connect is based on "pc-ble-driver-js", the "numerical comparison" method is a difference between pc-ble-driver-py and pc-ble-driver-js ? Both shouldn't have the same functionalities ?

    Best regards,

    Antoine

  • Hi Antoine, 

    I am no expert in the pc-ble-driver, just reading and reviewing the code along with you for the first time, but I have good experience with BLE.

    SoftDevice sends ble_gap_evt_passkey_display_t with both the six-digit passkey and a match_request bit; when match_request=1 you must reply with sd_ble_gap_auth_key_reply to accept/reject the comparison. pc-ble-driver-py seems to be dropping that flag, do not know why. So your script never knows to confirm and the pairing stalls. To fix this you must extend the feature by carrying the match_request through BLEGapPasskeyDisplay, forward it in the ble_driver and observers and update your handler to call sd_ble_gap_auth_key_reply with the proper key when match_request is true.  I do not have any sample or code snippets to show you but I think this most likely seems to be the reason.

  • Hi Shusheel,

    Thank you for the reply !

    I just update pc-ble-driver-py following your response to have the code below:

    - ble_driver:

    elif evt_id == BLEEvtID.gap_evt_passkey_display:
        for obs in self.observers:
            passkey = BLEGapPasskeyDisplay.from_c(ble_event.evt.gap_evt.params.passkey_display)
    
            obs.on_gap_evt_passkey_display(
                ble_driver=self,
                conn_handle=ble_event.evt.gap_evt.conn_handle,
                passkey=passkey.passkey,
                match_request=ble_event.evt.gap_evt.params.passkey_display.match_request
            )

    - observers:

    def on_gap_evt_passkey_display(
        self, ble_driver, conn_handle, passkey, match_request):
        logger.debug(
            "evt> passkey_display conn({}) passkey({}), match_request({})\n".format(
                conn_handle, passkey, match_request
            )
        )

    - On my test script:

    def on_gap_evt_passkey_display(self, ble_driver, conn_handle, passkey, match_request): # Reached with IOCaps = keyboard_display/none/yesno
        self.logger.info("Central on_gap_evt_passkey_display: {}".format(passkey))
        ascii_passkey = ''.join(map(chr, passkey))
        self.logger.info(f"Central on_gap_evt_passekey_display (ASCII): {ascii_passkey}")
        passkeyQueue.put(passkey)
        
        if match_request:
            # Send passkey as it has been printed on display
            pk = util.list_to_uint8_array(passkey) #b"\0")#
            driver.sd_ble_gap_auth_key_reply(self.adapter.driver.rpc_adapter,conn_handle,driver.BLE_GAP_AUTH_KEY_TYPE_PASSKEY, pk.cast())
    

    The "match_request" parameter is correctly set to 1 so the "if match_request" condition is True and sd_ble_gap_auth_key_reply is reached as expected.

    But I still got issue with bonding as status returned is:

    result = self.adapter.evt_sync[self.conn_handle].wait(BLEEvtID.gap_evt_auth_status)
    
    #=> result = {'error_src': 0, 'bonded': 0, 'sm1_levels': <pc_ble_driver_py.lib.nrf_ble_driver_sd_api_v5.ble_gap_sec_levels_t; proxy of <Swig Object of type 'ble_gap_sec_levels_t *' at 0x000002CBAD782370> >, 'sm2_levels': <pc_ble_driver_py.lib.nrf_ble_driver_sd_api_v5.ble_gap_sec_levels_t; proxy of <Swig Object of type 'ble_gap_sec_levels_t *' at 0x000002CBAE474FF0> >, 'kdist_own': <pc_ble_driver_py.ble_driver.BLEGapSecKDist object at 0x000002CBAE474C40>, 'kdist_peer': <pc_ble_driver_py.ble_driver.BLEGapSecKDist object at 0x000002CBAE474C70>, 'auth_status': <BLEGapSecStatus.timeout: 1>}

    Is there something else to perform numerical comparison ? Like sending something else than just the passkey ? Or waiting for an event that I could miss and not set the hanlder ?

    Best regards,

    Antoine

  • Quick update on the topic:

    The function "sd_ble_gap_auth_key_reply" return the value: 7

    resp = driver.sd_ble_gap_auth_key_reply(self.adapter.driver.rpc_adapter, conn_handle, driver.BLE_GAP_AUTH_KEY_TYPE_NONE, pk.cast())

    From https://docs.nordicsemi.com/bundle/s145-latest/page/group_nrf_error_ga0a5831cf5092e0dd43a01869676ee076.html#ga0a5831cf5092e0dd43a01869676ee076, it's look like 7 means NRF_ERROR_INVALID_PARAM.

    Still with the documentation (https://docs.nordicsemi.com/bundle/s145-latest/page/group_BLE_GAP_FUNCTIONS_ga01e04f368c8e7b3aaa31740dbd53bd12.html#ga01e04f368c8e7b3aaa31740dbd53bd12), function "sd_ble_gap_auth_key_reply" only have 3 parameters (conn_handle, key_type, p_key). But in the pc-ble-driver-py, this function have 4 parameters ("adapter" added). Why there is this difference ?

    Does somone know what could cause NRF_ERROR_INVALID_PARAM ?

    Best regards,

    Antoine

  • Last update:

    Following this spec : https://docs.nordicsemi.com/bundle/s145-latest/page/group_BLE_GAP_FUNCTIONS_ga01e04f368c8e7b3aaa31740dbd53bd12.html#ga01e04f368c8e7b3aaa31740dbd53bd12

    NULL must be used instead of passkey when confirming LE Secure Connections Numeric Comparison.

    Code must be adapted as below:

        def on_gap_evt_passkey_display(self, ble_driver, conn_handle, match_request, passkey): # Reached with IOCaps = keyboard_display/none/yesno
            self.logger.info("Central on_gap_evt_passkey_display: {}".format(passkey))
            ascii_passkey = ''.join(map(chr, passkey))
            self.logger.info(f"Central on_gap_evt_passekey_display (ASCII): {ascii_passkey}")
    
            if match_request:
                resp = driver.sd_ble_gap_auth_key_reply(self.adapter.driver.rpc_adapter, conn_handle, driver.BLE_GAP_AUTH_KEY_TYPE_PASSKEY, None)
                self.logger.info(f"auth_key_reply return value: {resp}")

    I tried with b'\0' for NULL character but only work with "None".

    Anyway, numerical comparison is available following the details posted by   (thanks again !) and using 'None' instead of 'pk.cast()'

Related