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

BLE using Notify of length less than current MTU size issue

Hello, 

I am tinkering with some BLE configurations specifically related to MTU and throughput optimization, and my question relates to using Notify on my attribute value and how it relates to the currently set MTU size in a connection. 

I am using the following part, SD and SDK: 

NRF52832

SD132 v5.1

SDK v14.2

My device is running as a BLE peripheral Server, there is a mobile application connecting to it as a client. 

The client is subscribing to a characteristic which my device then uses Notify to send data to the mobile app client which works fine. In order to notify on the attribute I am using the standard function from the SD API:

uint32_t sd_ble_gatts_hvx

(

uint16_t 

conn_handle,

 

 

ble_gatts_hvx_params_t const * 

p_hvx_params 

 

)

 

 

My question centers around the data length specified in the “p_hvx_params” field and how that relates to the MTU size and what actually gets sent to the device. 

I am seeing a mismatch in what I set for the “p_hvx_params->p_len” and what actually gets sent to the mobile application. Every notify, the app sees the amount of data sent as the currently set MTU size, and not what I set for p_hvx_params->p_len.

For example, say I connect to the mobile app and MTU size is being set to 100 bytes. If I want to do a Notify less than 100 bytes, Iet's say 10 bytes, I do the following essentially: 

uint16_t len = 10;

p_hvx_params->p_len = &len;

sd_ble_gatts_hvx(conn_handle, p_hvx_params);

 

The mobile app is claiming to receive 100-3 bytes = 97 bytes of the data I send padded with 0s. This is the MTU size, - ATT header (3 bytes). I am expecting it to receive 10 bytes. 

 

So in summary, my question boils down to: As a peripheral server device, can you do a BLE Notify on a characteristic of length less than the MTU and am I doing it wrong with example code above? Maybe there is some configuration or step I am missing here. 

 

It is entirely possible there is a mobile application bug and I really am sending up data correctly, but interacting with other non-Nordic MCUs, the app is able to receive less data than the MTU length no problem, wondering if there is a specific difference with the Nordic SD here or I am doing something wrong. My next step is to get a sniffer setup to try and debug, but wanted to leave a post here to see if anyone has any advice or help they could give me.

Parents
  • Hello,

    As you mention, I also suspect that this might be an issue on the smartphone side. With a sniffer trace we would be able to pinpoint exactly which side the issue is on, and it would be very helpful if you could capture one and share here. We could then see exactly what is being sent on-air. The SoftDevice does not add padding to meet the maximal MTU size - this would be very wasteful in terms of power and radio time. Without seeing more code, or a trace, there is little more I can say at this point.

    I also notice in the code you use to illustrate the notification queueing that you are not checking the returned error code from sd_ble_gatts_hvx - this might have been omitted since it was besides the point you were illustrating, but I need to ask just in case.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

  • Hello! Awesome thanks for the help, ok got some BLE sniffer captures to look at. 

    My device is connecting to a mobile app and the MTU is getting set to 185.  I am doing a Notification using the SD function: 

    sd_ble_gatts_hvx(conn_handle, p_hvx_params);

    In order to try to make this easy, I am doing 2 consecutive notifications on the same characteristic to make it easy to see in the BLE sniffer captures. 

    1. First a Notification of 50 bytes of all  0xAA

    2. Then a Notification of only 10 bytes of incrementing values : 1,2,3,4,5,6,7,8,9,10

    For reference, here are the two functions I am using to accomplish this:

    static uint32_t Write1(void)
    {
       uint16_t conn_handle = BLE__GetConnectionHandle();
       uint8_t new_data[50] = {0};
       uint16_t char_handles = BLE__GetUplinkValueHandle();
       uint16_t len = 50;
       uint32_t err_code = NRF_SUCCESS;
       ble_gatts_hvx_params_t params;
    
       memset(new_data, 0xAA, 50);
    
       if (conn_handle != BLE_CONN_HANDLE_INVALID)
       {
          memset(&params, 0, sizeof(params));
          params.type   = BLE_GATT_HVX_NOTIFICATION;
          params.handle = char_handles;
          params.offset = 0;
          params.p_data = new_data;
          params.p_len  = &len;
          err_code      = sd_ble_gatts_hvx(conn_handle, &params);
       }
      
       return err_code;
    }

    static uint32_t Write2(void)
    {
       uint16_t conn_handle = BLE__GetConnectionHandle();
       uint8_t new_data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
       uint16_t char_handles = BLE__GetUplinkValueHandle();
       uint16_t len = 10;
       uint32_t err_code = NRF_SUCCESS;
       ble_gatts_hvx_params_t params;
    
       if (conn_handle != BLE_CONN_HANDLE_INVALID)
       {
          memset(&params, 0, sizeof(params));
          params.type   = BLE_GATT_HVX_NOTIFICATION;
          params.handle = char_handles;
          params.offset = 0;
          params.p_data = new_data;
          params.p_len  = &len;
          err_code      = sd_ble_gatts_hvx(conn_handle, &params);
       }
         
       return err_code;
    }

    Now, here is what I am seeing on the Wireshark BLE sniffer capture, both messages are marked . From what I can tell, both are getting written with lengths of 185, which is what is set for the MTU length. 

    Here is the first notification selected I believe:

    You can see the 50 bytes of 0xAA, followed by garbage, and it is stating the length in the L2CAP header is 185. 

    The second notification/write is showing the following:

    You can see the first 10 bytes set to {1, 2, 3....10}, followed by the rest of 0xAA bytes from previous write, then same garbage. 

    Is there anything you are seeing here that seems odd or jumps out? I am a little lost as to what I could be doing wrong, or what else I can do to send in a "Notify" less than 185 bytes (MTU size). Please let me know if there is any additional information you need or clarifications. 

    I am working with both Android and iOS engineers, and they are giving me the same feedback that the notifications are the same size as the MTU, and sniffer seems to prove them right from what I can tell. 

  • Hello, 

    tlgage said:
    Awesome thanks for the help

    No problem at all, I am happy to help!

    tlgage said:
    ok got some BLE sniffer captures to look at. 

    Fantastic, that will be really helpful to take a look at!
    It is best if you share the entire sniffer trace with me, and then instead detail what you would like me to take a look at in particular, or what you have questions about - it is a lot easier if I can take a look at the complete sniffer trace myself, since I then have all the information. For example, if you share the full trace and ask questions directly about it; "You can see the issue in the exchange starting on packet #3346 - here the notification length is...", for instance.

    tlgage said:
    For reference, here are the two functions I am using to accomplish this:

    Thank you for providing the code - this is also helpful for me to have seen.
    Could you confirm for me that you always check the Write1 and Write2 functions returned error codes with an APP_ERROR_CHECK? This will alert you in case a packet fails to queue for sending - which in turn could skew what you have expected to see, compared to what was actually transmitted.

    tlgage said:

    From what I can tell, both are getting written with lengths of 185, which is what is set for the MTU length. 

    Here is the first notification selected I believe:

    This is hard for me to say exactly without the full sniffer trace, but it looks to me that the length of packet #4578 is actually 90, and packet #4580 is 189 - which is strange if your MTU size really is 185 (this assumes you have setup wireshark to display packet length in 4th column, and might not be the case).
    Additionally, it says that the L2CAP has a length of 185 (MTU size), not necessarily the received packet.
    If you attempt to queue more data than the MTU size allows, the L2CAP will fragment the packet, and send it as multiple packets. This might be what you are seeing, for example if you are calling your write functions multiple times, or if some of these calls fail.
    How often / how is your write functions called? Is it only once, during the entire connection, or periodically/continuously? 

    Looking forward to resolving this issue together!

    Best regards,
    Karl

  • wireshark_log_notification.pcapng

    Sure, just uploaded a log of a wireshark capture. There is a lot going on for general BLE interaction, what I am focusing in on is isolating the 2 functions Write1 and Write2 from my previous post. 

    From the log you can see packets No. 451, and 455 that refer to the 2 notification/write functions on Handle 0x0010. 

    I also verified the return value on the sd_ble_gatts_hvx(conn_handle, p_hvx_params); is returning NRF_SUCCESS, and verified with APP_ERROR_CHECK. 

    The write functions are each called only once. There are other notifications called in other areas of the code, which is what you see with all the other BLE activity, but the two functions from previous post I can confirm are only each being called once. 

Reply
  • wireshark_log_notification.pcapng

    Sure, just uploaded a log of a wireshark capture. There is a lot going on for general BLE interaction, what I am focusing in on is isolating the 2 functions Write1 and Write2 from my previous post. 

    From the log you can see packets No. 451, and 455 that refer to the 2 notification/write functions on Handle 0x0010. 

    I also verified the return value on the sd_ble_gatts_hvx(conn_handle, p_hvx_params); is returning NRF_SUCCESS, and verified with APP_ERROR_CHECK. 

    The write functions are each called only once. There are other notifications called in other areas of the code, which is what you see with all the other BLE activity, but the two functions from previous post I can confirm are only each being called once. 

Children
  • Hello,

    tlgage said:
    Sure, just uploaded a log of a wireshark capture. There is a lot going on for general BLE interaction, what I am focusing in on is isolating the 2 functions Write1 and Write2 from my previous post.

    Thank you for providing the sniffer trace - this makes it much easier for me to have a look.
    From the capture we clearly see that the zeroes are being sent on-air, and so the packet is extended by a lot of useless data queued for transfer.
    We clearly see that the other notifications sent by your application are not zero padded, so at least that falsifies the notion about the SoftDevice padding the message with zeros, so we need to look into what the application might be doing here exactly. It is curious that the size of the message matches the MTU size. Could you possibly have used the MTU size as a length parameter elsewhere in the application?

    tlgage said:
    From the log you can see packets No. 451, and 455 that refer to the 2 notification/write functions on Handle 0x0010. 
    tlgage said:
    The write functions are each called only once. There are other notifications called in other areas of the code, which is what you see with all the other BLE activity, but the two functions from previous post I can confirm are only each being called once. 

    I see that the handle 0x0010 is updated multiple times throughout the capture - I take it that this means it is used elsewhere in your application, along with this test?
    Could you show me all the code that updates and has to do with the BLE__GetUplinkValueHandle notification handle?
    I dont see any reason how the code snippets you have sent so far could generate this zero padding, so I am interested in seeing all code that configured and queues data for sending on the 0x0010 handle.

    tlgage said:
    I also verified the return value on the sd_ble_gatts_hvx(conn_handle, p_hvx_params); is returning NRF_SUCCESS, and verified with APP_ERROR_CHECK. 

    Great, thank you for confirming.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

Related