Cannot alter MTU after connecting a peripheral device using the python library "pc_ble_driver_py"

Hello, 

I'm using the nRF device to communicate with a peripheral device I get some characteristic notifications but only 20 bytes for a packet.

When using the 'nRF connect' GUI I manage to update the MTU from 23 to any larger value and get the full notification.

But I cannot alter MTU after connecting a peripheral device using the python library "pc_ble_driver_py".

Iv'e tried many ways like setting the default_mtu and the att_mtu on adapter initialization:

driver = BLEDriver(
    serial_port=port,
    auto_flash=auto_flash,
    baud_rate=baud_rate,
    retransmission_interval=retransmission_interval,
    response_timeout=response_timeout,
    log_severity_level=driver_log_level,
)
driver.ble_gattc_exchange_mtu_req
adapter = BLEAdapter(driver)
adapter.default_mtu = 247
adapter.driver.open()
gatt_cfg = BLEConfigConnGatt()
gatt_cfg.att_mtu = adapter.default_mtu
adapter.driver.ble_cfg_set(BLEConfig.conn_gatt, gatt_cfg)
adapter.driver.ble_enable()


And to use the adapter.att_mtu_exchange function to but for no avail.
when i execute tyhe command : 
self.ble_adapter.att_mtu_exchange(self.conn_handler, 23)
 

it's running fine but when i try to increece the mtu to a different level like:
self.ble_adapter.att_mtu_exchange(self.conn_handler, 247)
 (or any number greater then 23)

it allways raise the folowing exception:

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.

Is there any way to overcome this hurdle?

Thanks,
Uri


Parents
  • Hi uri_ee,

    I will support you with this case. However, I will need to do some investigation, while there is a bit too much on my schedule at the moment; so I cannot give you an answer right away.

    I'm sorry for the inconvenience. Unless someone from the community already helped you then, I will return by the end of Friday Mar 17

    Hieu

  • Hi uri_ee,

    My apology but I have still been occupied and haven't been able to start looking into this yet. I will try to get to it within next week, likely before Wednesday.

    Hieu

  • I am a bit surprised. Do you not even have a MTU higher than 23 at all?

    As you can see in the second screenshot in my last reply, when I set the default_mtu field to 121, the negotiation happened automatically, and the two devices successfully agreed on 121 as the MTU.

    That experiment was based on the heart_rate_collector.py example. When I tried the code unmodified, I observed the negotiation to ended with MTU of 247 instead.

    How are you setting up your project? Can you try to use the HRS sample unmodified and see if the MTU is updated automatically? 

  • Hieu said:

    I believe the idea is that the first MTU exchange should have already set MTU to the highest value both the Client and the Server can support, so there is no need to set it to any other value.

    While it could be inconsequential, this seems a bit too inflexible and basically render this API meaningless after the first MTU exchange. That makes me doubt my own understanding. I am out of office until the end of the week, but I will double check in the Bluetooth spec and with my team next week.

    Following up on this point, it is required by the Bluetooth Core Specification, Vol 3, Part G, Section 4.3.1 Exchange MTU:

    4.3.1 Exchange MTU
    This sub-procedure is used by the client to set the ATT_MTU to the maximum
    possible value that can be supported by both devices when the client supports
    a value greater than the default ATT_MTU for the Attribute Protocol. This subprocedure
    shall only be initiated once during a connection.

  • How are you setting up your project? Can you try to use the HRS sample unmodified and see if the MTU is updated automatically? 

    Hello Hieu.

    I run the HRS example code but cannot find any reference to the MTU setting in logs.

    Can you please instruct me.

  • Hi Uri,

    The MTU log in my screenshot is from the HRS device. With a device running the HRS example, without any modification necessary, you should see it log by default via UART (which is connected to a Virtual COM port in our development kits).

    If you have difficulty seeing that or if you are using a different hardware, please give me some details and I will see if there is an alternative.

    Please also note that it is the Easter holiday at my location, and my responses would be delayed due to a staffing situation, and my being out of office from Wednesday this week. I am sorry for the inconvenience.

  • Hello Hieu.

    If you have difficulty seeing that or if you are using a different hardware, please give me some details and I will see if there is an alternative.

    Yes, i would need That alternative.

Reply Children
  • Hi Uri, then you need to give me some details of your setup. What hardware are you using? Why can you not connect UART to get log? What interface options do you have with it? As much as possible

  • Hello Hieu.

    After consulting the device manager, it appears that there is no reliable method to connect to the internal logs of the device.

    I want to reiterate that when using the GUI provided by Nordic, the MTU can be updated once.

    Are there any alternative solutions we can explore to address the MTU updating this issue?

  • Hello Uri,

    If you can update MTU once, and not again, then the behavior is expected. Please refer to Bluetooth Core Spec Version 4.0/5.0/5.4 | Vol 3, Part G, Section 4.3.1 Exchange MTU

    This sub-procedure is used by the client to set the ATT_MTU to the maximum possible value that can be supported by both devices when the client supports a value greater than the default ATT_MTU for the Attribute Protocol. This subprocedure shall only be initiated once during a connection.
  • Hello Hieu.

    The Problem is that I can only update the MTU from the GUI not from Python script.

  • Hi Uri,

    I looked into it finally understood (maybe) everything. 

    On the Peripheral/nRF device side, the ble_app_hrs example by default initiates the MTU exchange first because NRF_BLE_GATT_MTU_EXCHANGE_INITIATION_ENABLED is set.

    If you set that config to 0, then the Peripheral will not initiate the negotiation, and from the Python side, you can initiate the negotiation. I did this with:

        if conn is not None:
            try:
                adapter.driver.ble_gattc_exchange_mtu_req(conn_handle=conn, mtu=129)
            except Exception as ex:
                logger.exception("Exception ble_gattc_exchange_mtu_req: {}".format(ex))

    You cannot see the final MTU, but you can derive it by looking into parameters of certain functions using breakpoints.

    Note that breakpoints can break a connection depends on where it is set. If you don't want to have to think too much about it, just restart the experiment from the beginning after each "sampling" using breakpoints.

    If the nRF device side initiates the negotiation,

    If the Python side initiates the negotiation,

    Then the MTU will be decided as the minimal between both sides' preferred MTUs. 

Related