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

What happens if you send more than 20 bytes in one packet, when using notifications and NUS?

Hey, so I was under the belief that the maximum size of data one can include in a BLE packet is 20 bytes (23 bytes total, 3 bytes overhead, so 20 total for custom data). With this constraint, I was evaluating how to send data that would be larger than 20 bytes if sent as human-readable ASCII digits. An example of the data would be as follows:

2.25,21.0, 24.0,1342,2512,0873,36.6,2899

If I encode every digit as an ASCII char to be human readable, including commas (and a '\n' at the end), this comes to 40 bytes total. So, I was considering pros and cons of sending two packets each 20 bytes long per "set of data", and having my custom mobile app handle this accordingly. I was also considering a more complicated packing strategy, where I do something along the lines of multiply float values by 100 then cast all values to uint16_t, store into packet without commas, and have mobile app unpack accordingly. This would fit everything into 20 bytes, but would no longer be human readable and be more difficult to debug.

Just a few minutes ago, I wanted to see what happens if I try to send all 40 bytes as human readable ASCII. I made the following call:

uint8_t test_packet[] = {48,48,48,48,44,48,48,48,48,44,
                         48,48,48,48,44,48,48,48,48,44,
                         48,48,48,48,44,48,48,48,48,44,
                         48,48,48,48,44,48,48,48,48,10};
uint16_t size = 40;
ble_nus_data_send(&m_nus, test_packet, &size, m_conn_handle);

to test sending a packet that would look like "0000,0000,0000,0000,0000,0000,0000,0000\n".  I did not change anything else in my nRF application, nor change any settings in the central device. I used the Adafruit Bluefruit LE Connect generic UART plotter/receiver app, and this is what I got:

To my surprise, it worked perfectly fine. After doing some more reading, it appears like only BLE 4.1 devices have the 20 byte constraint. Is there anything I should be concerned about when sending 40 bytes in one package? Does anybody have more information on what central devices (specifically mobile phone models) will be constrained to BLE 4.1 or the 20 byte payload restriction? If sending 40 bytes per packet is a "safe" thing to do, then for my application this is the optimal design choice for right now. Any input would be greatly appreciated.

I am using nRF 52 DK, but plan to flash this firmware onto an nRF52810 on a custom board. Developing with SDK V 15.2.0, and using Nordic UART Service to transmit data.

Parents
  • There is a MTU negotiation right after the connection is established. The max MTU can come up to 244 bytes depending on the central.

    If you have a look at the code you will see that a call to nrf_ble_gatt_init() with a pointer to a handler function is made

    Then nrf_ble_gatt_att_mtu_periph_set() is called, with the desired MTU (the max allowed = 244)

    The MTU negotiation takes place and you get a NRF_BLE_GATT_EVT_ATT_MTU_UPDATED event in the event handler with the maximum MTU agreed between both central and peripheral which is usually the most restrictive of the two.

    After that you can send NUS payloads of up to that MTU. Packets are internally fragmented into 20-byte blocks (or more if DLE is supported) and reassembled in the central transparently.

    Depending on the example you are using (<InstallFolder>\examples\ble_peripheral\ble_app_uart) there might also be a ring buffer that allows you to enqueue arbitrary sized messages as long as there is space in the buffer and they will be sent in chunks as big as possible (up to the negotiated MTU)


    Have a look at this thread: devzone.nordicsemi.com/.../maximum-att-mtu-for-ble-nus

  • Yeah this makes sense, I am familiar with these events and the MTU negotiation. I guess I never really thought further than "seems like 20 bytes is the max, so I'll just stick with that" until now. 

    However, this could become an issue if the central does not agree upon a 40 byte + MTU, correct? If my app is installed onto a very old iPhone, with an old version of iOS that only supports BLE 4.1 and not BLE 4.2/5.0+, then I would not be able to send 40 byte packets? I have also read 4.2 and 4.1/4.0 are back compatible, does this mean sending 40 bytes will still work because of the internal 20-byte fragmentation? I am using the ble_app_uart as the core for my application

  • I would say that you should account for a negotiated MTU of 20 bytes in the worst-case scenario and do the fragmentation-reassembly yourself.
    Taking the max MTU into account can be useful however when you want to transfer bulk data and maximize the throughput.

    But if you are using the ble_app_uart this is hidden behind the FIFO buffer. If the negotiated MTU is 20 and you send 40 bytes, they will be enqueued and sent 20 bytes at a time. The central will see 2 notifications, so I would advise adding a header to your message to identify the first notification and decode the rest of the message from there.

Reply
  • I would say that you should account for a negotiated MTU of 20 bytes in the worst-case scenario and do the fragmentation-reassembly yourself.
    Taking the max MTU into account can be useful however when you want to transfer bulk data and maximize the throughput.

    But if you are using the ble_app_uart this is hidden behind the FIFO buffer. If the negotiated MTU is 20 and you send 40 bytes, they will be enqueued and sent 20 bytes at a time. The central will see 2 notifications, so I would advise adding a header to your message to identify the first notification and decode the rest of the message from there.

Children
No Data
Related