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

Unable to change MTU size pc-ble-driver-py

Hello,

I am playing around with pc-ble-driver-py to make a connection towards a BLE peripheral. The peripheral is using a custom service very similar to the Nordic UART Service. I have managed to get it working but I am unable to exchange the MTU size and is stuck with the 23 bytes default MTU.

I have been looking into other code examples and this is what I'm trying to do:

CFG_TAG = 1
nrf_sd_ble_api_ver = config.sd_api_ver_get()
assert nrf_sd_ble_api_ver == 5

# Setup BLEDriver and BLEAdapter
driver = BLEDriver(
    serial_port='/dev/tty.usbmodem0006826680971',
    auto_flash=False,
    baud_rate=1000000,
    log_severity_level="info"
)
adapter = BLEAdapter(driver)

# Later in code
cfg = BLEConfigGapRoleCount(central_role_count=1, periph_role_count=0, central_sec_count=0)
cfg.conn_cfg_tag = CFG_TAG
self.adapter.driver.ble_cfg_set(BLEConfig.role_count, cfg)

cfg = BLEConfigConnGatt(att_mtu=Central.LOCAL_ATT_MTU) # Central.LOCAL_ATT_MTU = 247
cfg.conn_cfg_tag = CFG_TAG
self.adapter.driver.ble_cfg_set(BLEConfig.conn_gatt, cfg)

cfg = BLEConfigConnGap(event_length=320)
cfg.conn_cfg_tag = CFG_TAG
self.adapter.driver.ble_cfg_set(BLEConfig.conn_gap, cfg)

self.adapter.driver.ble_enable()
self.adapter.driver.ble_vs_uuid_add(Central.BASE_UUID)


# Start scan, find device and connect
self.adapter.connect(peer_addr, tag=CFG_TAG)


logging.info('MTU Size: {}'.format(self.adapter.db_conns[self.conn_handle].att_mtu))    # Prints 23
if Central.LOCAL_ATT_MTU > ATT_MTU_DEFAULT:
    logging.info('Requesting MTU exchange')
    self.att_mtu = self.adapter.att_mtu_exchange(self.conn_handle, Central.LOCAL_ATT_MTU)

    max_data_length = 251
    data_length = self.att_mtu + 4
    if data_length > max_data_length:
        data_length = max_data_length
    self.adapter.data_length_update(self.conn_handle, data_length)

Here i get error message:

2020-11-11 10:03:09,265 root         INFO     Requesting MTU exchange
Traceback (most recent call last):
  File "/test/venv/lib/python3.7/site-packages/pc_ble_driver_py/ble_adapter.py", line 220, in att_mtu_exchange
    self.driver.ble_gattc_exchange_mtu_req(conn_handle, mtu)
  File "/test/venv/lib/python3.7/site-packages/pc_ble_driver_py/ble_driver.py", line 107, in wrapper
    error_code=err_code,
pc_ble_driver_py.exceptions.NordicSemiException: Failed to ble_gattc_exchange_mtu_req. Error code: NRF_ERROR_INVALID_PARAM

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/test/test.py", line 227, in <module>
    central.start()
  File "/test/test.py", line 133, in start
    self.att_mtu = self.adapter.att_mtu_exchange(self.conn_handle, Central.LOCAL_ATT_MTU)
  File "/test/venv/lib/python3.7/site-packages/pc_ble_driver_py/ble_adapter.py", line 225, in att_mtu_exchange
    "different config tags used in ble_cfg_set and connect.") from ex
pc_ble_driver_py.exceptions.NordicSemiException: MTU exchange request failed. Common causes are: missing att_mtu setting in ble_cfg_set, different config tags used in ble_cfg_set and connect.

Any suggestion how to proceed with this?

  • Hi,

    As described in the API documentation for sd_ble_gattc_exchange_mtu_request(), NRF_ERROR_INVALID_PARAM is thrown when "Invalid Client RX MTU size supplied". Further, the valid Client RX MTU sizes are:

    The two first seems to match your code. Have you captured a sniffer trace to see if the server side initiates a MTU exchange first?

    Best regards,
    Jørgen

  • Hello and thanks for answer, it seems like this is initiated by the server. I put a breakpoint in ble_driver.py in function on_gatts_evt_exchange_mtu_request and that did occur. The BLEAdapter.att_mtu_exchange does update the MTU on successful response (self.db_conns[conn_handle].att_mtu = new_mtu) but the callback on_gatts_evt_exchange_mtu_request does not. I need to register an observer to this callback to update it locally.

  • So, now i can see the new MTU, but i get error when trying to write bigger pakages:

        def write(self, data):
            payload = struct.pack('<i', len(data)) + data
            mtu = self.packet_size
    
            written = 0
            for i in range(0, len(payload), mtu):
                chunk = payload[i:i + mtu]
                logging.info('Writing ({}) {}'.format(len(chunk), hex_rep(chunk)))
                status = self.adapter.write_req(
                    self.conn_handle,
                    None,
                    chunk,
                    self.rx_char
                )

    I get error NRF_ERROR_SD_RPC_NO_RESPONSE

    2020-11-12 10:12:05,546 root         INFO     Writing (46) 2a00000053437632010000000000ee565675de5bfb7f26a773b11b3a9974adfb8d2ceaf0c3a62a1d432376d3197a
    
    
      File "ble_driver.py", line 101, in wrapper
        err_code = wrapped(*args, **kwargs)
      File "ble_adapter.py", line 487, in write_req
        self.driver.ble_gattc_write(conn_handle, write_params)
      File "ble_driver.py", line 107, in wrapper
        error_code=err_code,
    pc_ble_driver_py.exceptions.NordicSemiException: Failed to ble_gattc_write. Error code: NRF_ERROR_SD_RPC_NO_RESPONSE

  • From your serial port path, it looks like you are using MacOS, is that correct? In that case, I'm suspecting this J-Link limitation to cause this issue. Can you please try "Workaround 2" suggested on the linked page?

  • Thats correct, i'll try this.
    I remember having some JLink issue earlier also. Instead of using pc-ble-driver(-py) i used a custom firmware specific for my service, and then custom UART commants to bridge data. But in order to get it working properly i changed the UART pins and used a FTDI cable to get better stability. 

    Now i get longer, and get stuck on:
    pc_ble_driver_py.exceptions.NordicSemiException: Failed to ble_gattc_write. Error code: NRF_ERROR_DATA_SIZE

    - BLEAdapter.gatts_evt_exchange_mtu_request is called and BLEDriver.ble_gatts_exchange_mtu_reply occurs
    - MyCode.gatts_evt_exchange_mtu_request is happening and i am updating how big packages can be sent (mtu - 3 => 244 bytes)

    Are there any other configuration steps that i am missing?
    I'm trying to compare against my custom FW and see what have been done there.


Related