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

  • 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.

    I actually do not totally agree with this statement. What I see is, between the characteristic size and the current MTU size, the smallest value I am able to send is the minimum of those two values. Let me know if that does not make sense.

    For example, the characteristic in question 0x0010, is sized at 255, and MTU is set at 185 on connection, minimum size I see being sent is 185. Now if you look at a different handle, say 0x0013 I am also sending notifications on, you can see it is only 1 byte of data. That particular characteristic size is only 1 byte long. If I increase the characteristic length, I see that length getting sent increase as well, until it reaches the MTU size, then MTU size is the minimum size being sent. Same thing with handle 0x0032, that characteristic is 20 bytes long, I am unable to send anything less that 20 bytes at a time using a notification. 

    Happy to be proved wrong on this if you see an example in the trace of something different, but I am seeing this apply for all characteristics. 

    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?

    Interesting point now that you bring it up. So the max size I send at once is the current MTU size - 3, leftover data for the last message, which is less than MTU size, I send separately. So for example, if the MTU size is 185, and I want to send 200 bytes of data, I will send 1 message with 182 bytes (MTU - ATT header of 3 bytes), then one message with 18 bytes. Wonder if I am doing that wrong. I wonder what happens if I try to Notification more than MTU size. I will actually play around with that and see what it looks like. 

    Could you show me all the code that updates and has to do with the BLE__GetUplinkValueHandle notification handle?

    Here is the function used to send data outside of the ones shared, I print the length for every write and see it print expected size, its pretty much a copy from the other functions I have shared.

    /**@brief Function to write on notification characteristics.
     *
     * @param[in] conn_handle   connection handle for the present connection.
     * @param[in] *new_data  pointer to data to be written.
     * @param[in] char_handles   value handle of characteristic to be written
     * @param[in] len  length of data/number of bytes to be written
     */
    static uint32_t notification_write(uint16_t conn_handle,
                                       uint8_t* new_data,
                                       uint16_t char_handles,
                                       uint16_t len)
    {
       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.p_data = new_data;
          params.p_len  = &len;
          err_code      = sd_ble_gatts_hvx(conn_handle, &params);
       }
    
       printf("Write Len = %d\r\n", *params.p_len);
      
       return err_code;
    }

Reply
  • 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.

    I actually do not totally agree with this statement. What I see is, between the characteristic size and the current MTU size, the smallest value I am able to send is the minimum of those two values. Let me know if that does not make sense.

    For example, the characteristic in question 0x0010, is sized at 255, and MTU is set at 185 on connection, minimum size I see being sent is 185. Now if you look at a different handle, say 0x0013 I am also sending notifications on, you can see it is only 1 byte of data. That particular characteristic size is only 1 byte long. If I increase the characteristic length, I see that length getting sent increase as well, until it reaches the MTU size, then MTU size is the minimum size being sent. Same thing with handle 0x0032, that characteristic is 20 bytes long, I am unable to send anything less that 20 bytes at a time using a notification. 

    Happy to be proved wrong on this if you see an example in the trace of something different, but I am seeing this apply for all characteristics. 

    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?

    Interesting point now that you bring it up. So the max size I send at once is the current MTU size - 3, leftover data for the last message, which is less than MTU size, I send separately. So for example, if the MTU size is 185, and I want to send 200 bytes of data, I will send 1 message with 182 bytes (MTU - ATT header of 3 bytes), then one message with 18 bytes. Wonder if I am doing that wrong. I wonder what happens if I try to Notification more than MTU size. I will actually play around with that and see what it looks like. 

    Could you show me all the code that updates and has to do with the BLE__GetUplinkValueHandle notification handle?

    Here is the function used to send data outside of the ones shared, I print the length for every write and see it print expected size, its pretty much a copy from the other functions I have shared.

    /**@brief Function to write on notification characteristics.
     *
     * @param[in] conn_handle   connection handle for the present connection.
     * @param[in] *new_data  pointer to data to be written.
     * @param[in] char_handles   value handle of characteristic to be written
     * @param[in] len  length of data/number of bytes to be written
     */
    static uint32_t notification_write(uint16_t conn_handle,
                                       uint8_t* new_data,
                                       uint16_t char_handles,
                                       uint16_t len)
    {
       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.p_data = new_data;
          params.p_len  = &len;
          err_code      = sd_ble_gatts_hvx(conn_handle, &params);
       }
    
       printf("Write Len = %d\r\n", *params.p_len);
      
       return err_code;
    }

Children
No Data
Related