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

pc-ble-driver-py - sd_ble_gap_sec_params_reply fails

I have been using the pc-ble-driver Python bindings to implement a peripheral. I have extended BLEDriver to support sd_ble_gatts_* the functions. I now have a working peripheral, however I have a problem when trying to support bonding.

When the central tries to bond, my code receives a BLE_GAP_EVT_SEC_PARAMS_REQUEST event. I then call BleDriver.ble_gap_sec_params_reply. However the driver appears to hang at this point, as sd_ble_gap_sec_params_reply never returns (I don't even get an error code). I'm using the latest pc-ble-driver-py module on Linux with connectivity_1.0.1_115k2_with_s130_2.0.1.hex on a NRF51 development board.

UPDATE: I've changed the code to call sd_ble_gap_sec_params_reply on the main thread, as suggested by below. The call now returns instead of hanging, but fails with error code 3 (Internal Error). I've updated the below code to show this:

import sys
import time 
import logging
import threading

from pc_ble_driver_py.observers import BLEDriverObserver

logging.basicConfig(level=logging.DEBUG)

def init(conn_ic_id):
    global BLEDriver, BLEAdvData, BLEGapSecStatus, BLEGapSecParams, BLEGapIOCaps, BLEGapSecKDist
    from pc_ble_driver_py import config
    config.__conn_ic_id__ = conn_ic_id
    from pc_ble_driver_py.ble_driver import BLEDriver, BLEAdvData, BLEGapSecStatus, BLEGapSecParams, BLEGapIOCaps, BLEGapSecKDist

class PeripheralTest(BLEDriverObserver):

    def on_gap_evt_connected(self, ble_driver, conn_handle, peer_addr, role, conn_params):
        print('on_gap_evt_connected - conn_handle: {} role: {}'.format(conn_handle, role))

    def on_gap_evt_disconnected(self, ble_driver, conn_handle, reason):
        print('on_gap_evt_disconnected - conn_handle: {} reason: {}'.format(conn_handle, reason))

    def on_gap_evt_sec_params_request(self, ble_driver, conn_handle, peer_params):
        print('on_gap_evt_sec_params_request - conn_handle'.format('conn_handle'))
        for k in ('bond', 'mitm', 'lesc', 'keypress', 'io_caps', 'oob', 'min_key_size', 'max_key_size'):
            val = getattr(peer_params, k)
            print('\t{}: {}'.format(k, val))
        self.sec_params_requested = (ble_driver, conn_handle)
        
    def do_sec_params_reply(self):
        ble_driver, conn_handle = self.sec_params_requested
        self.sec_params_requested = None
        sec_params = BLEGapSecParams(bond = 1, mitm = 0, lesc = 0,keypress = 0, io_caps = BLEGapIOCaps.none, oob = 0, 
            min_key_size = 7, max_key_size = 16,
            kdist_own = BLEGapSecKDist(enc=1, id=1, sign=0, link=0),
            kdist_peer = BLEGapSecKDist(enc=1, id=1, sign=0, link=0))
        
        # this is now called on the main thread, but returns error code 3 - NRF_ERROR_INTERNAL
        ble_driver.ble_gap_sec_params_reply(conn_handle, BLEGapSecStatus.success, sec_params, None, None)

    def loop(self):
        self.sec_params_requested = None
        while True:
            if self.sec_params_requested:
                self.do_sec_params_reply()
            time.sleep(0.1)

def main(serial_port):
    print('Serial port used: {}'.format(serial_port))
    driver = BLEDriver(serial_port=serial_port, auto_flash=False)
    periph = PeripheralTest()
    driver.observer_register(periph)
    driver.open()
    driver.ble_enable()
    driver.ble_gap_adv_data_set(BLEAdvData(complete_local_name='Bond Test'))
    driver.ble_gap_adv_start()
    print('Started advertising')
    try:
        periph.loop()
    except KeyboardInterrupt:
        pass
    print('Closing')
    driver.close()

if __name__ == '__main__':
    serial_port = None
    if len(sys.argv) < 3:
        print("Please specify connectivity IC identifier (NRF51, NRF52) and serial port")
        exit(1)
    init(sys.argv[1])
    serial_port = sys.argv[2]
    main(serial_port)
    quit()
Parents
  • Hi Paul,

    We found it's a bug with the ble_driver that if you call ble_gap_sec_params_reply() inside an interrupt handler it will crash.

    So if you can instead set a flag and then execute the command in main loop it should be ok.

  • Using gdb, I found that the NRF_ERROR_INTERNAL is caused by a NRF_ERROR_TIMEOUT in H5Transport::send. I tried increasing the timeouts for sd_rpc_data_link_layer_create_bt_three_wire and sd_rpc_transport_layer_create but the error still occurs. I also enabled the log message handler for sd_rpc_open and got the following output:

    on_gap_evt_connected - conn_handle: 0 role: BLEGapRoles.periph
    12/ 0 <-  [02 13 00 00 00 47 00 10 0f 0f ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:4 ack#:3 payload_length:a data_integrity:1 header_checksum:76 err_code:0
        15 ->  []
                type:                 ACK reliable: no seq#:0 ack#:5 payload_length:0 data_integrity:0 err_code:0
    on_gap_evt_sec_params_request - conn_handle
    13/ 0 <-  [02 12 00 00 00 06 00 06 00 00 00 d0 07 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:5 ack#:3 payload_length:d data_integrity:1 header_checksum:45 err_code:0
        16 ->  []
                type:                 ACK reliable: no seq#:0 ack#:6 payload_length:0 data_integrity:0 err_code:0
    14/ 0 <-  [02 12 00 00 00 28 00 28 00 00 00 d0 07 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:6 ack#:3 payload_length:d data_integrity:1 header_checksum:44 err_code:0
        17 ->  []
                type:                 ACK reliable: no seq#:0 ack#:7 payload_length:0 data_integrity:0 err_code:0
        18 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        19 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        20 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        21 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
    Traceback (most recent call last):
    File "bond_test2.py", line 60, in <module>
        main(serial_port)
    File "bond_test2.py", line 46, in main
        driver.ble_gap_sec_params_reply(0, BLEGapSecStatus.success, sec_params, None, None)     
    File "/usr/local/lib/python2.7/dist-packages/pc_ble_driver_py/ble_driver.py", line 126, in wrapper
        raise NordicSemiException('Failed to {}. Error code: {}'.format(wrapped.__name__, err_code))
    pc_ble_driver_py.exceptions.NordicSemiException: Failed to ble_gap_sec_params_reply. Error code: 3
    

    edit: I compared the bytes in the debug output to the documented serialization for sd_ble_gap_sec_params_reply. The serialized message is 280 bytes long - but the documentation says it should be no longer than 148 bytes. So it would seem that the message is malformed and causing the connectivity firmware to crash.

    edit 2: i was looking at an old version of the docs. The encoding is correct, but I believe the error is caused by not filling in the ble_gap_sec_keyset_t struct correctly. I'll post the answer here if I manage to get it working.

Reply
  • Using gdb, I found that the NRF_ERROR_INTERNAL is caused by a NRF_ERROR_TIMEOUT in H5Transport::send. I tried increasing the timeouts for sd_rpc_data_link_layer_create_bt_three_wire and sd_rpc_transport_layer_create but the error still occurs. I also enabled the log message handler for sd_rpc_open and got the following output:

    on_gap_evt_connected - conn_handle: 0 role: BLEGapRoles.periph
    12/ 0 <-  [02 13 00 00 00 47 00 10 0f 0f ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:4 ack#:3 payload_length:a data_integrity:1 header_checksum:76 err_code:0
        15 ->  []
                type:                 ACK reliable: no seq#:0 ack#:5 payload_length:0 data_integrity:0 err_code:0
    on_gap_evt_sec_params_request - conn_handle
    13/ 0 <-  [02 12 00 00 00 06 00 06 00 00 00 d0 07 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:5 ack#:3 payload_length:d data_integrity:1 header_checksum:45 err_code:0
        16 ->  []
                type:                 ACK reliable: no seq#:0 ack#:6 payload_length:0 data_integrity:0 err_code:0
    14/ 0 <-  [02 12 00 00 00 28 00 28 00 00 00 d0 07 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:6 ack#:3 payload_length:d data_integrity:1 header_checksum:44 err_code:0
        17 ->  []
                type:                 ACK reliable: no seq#:0 ack#:7 payload_length:0 data_integrity:0 err_code:0
        18 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        19 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        20 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
        21 ->  [00 7f 00 00 00 01 47 00 10 03 03 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
                type:     VENDOR_SPECIFIC reliable:yes seq#:3 ack#:7 payload_length:118 data_integrity:1 header_checksum:66 err_code:0
    Traceback (most recent call last):
    File "bond_test2.py", line 60, in <module>
        main(serial_port)
    File "bond_test2.py", line 46, in main
        driver.ble_gap_sec_params_reply(0, BLEGapSecStatus.success, sec_params, None, None)     
    File "/usr/local/lib/python2.7/dist-packages/pc_ble_driver_py/ble_driver.py", line 126, in wrapper
        raise NordicSemiException('Failed to {}. Error code: {}'.format(wrapped.__name__, err_code))
    pc_ble_driver_py.exceptions.NordicSemiException: Failed to ble_gap_sec_params_reply. Error code: 3
    

    edit: I compared the bytes in the debug output to the documented serialization for sd_ble_gap_sec_params_reply. The serialized message is 280 bytes long - but the documentation says it should be no longer than 148 bytes. So it would seem that the message is malformed and causing the connectivity firmware to crash.

    edit 2: i was looking at an old version of the docs. The encoding is correct, but I believe the error is caused by not filling in the ble_gap_sec_keyset_t struct correctly. I'll post the answer here if I manage to get it working.

Children
No Data
Related