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()