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

s140 - GATTS Handle Value Notification

Hi everyone,

I am trying to understand the GATTS Handle Value Notification diagram.

From what I have understand so far is tha the soft device keeps a buffer (ATT table) where packets are placed before transmission. So each time calling sd_ble_gatts_hvx function the payload is stored in ATT table right?

With nRF52840 and s140 it is possible to transmit up to 6 packets in the same connection interval using notifications (with indications I think is just one packet?). The packets that have been stored in ATT table are transmitted in the next connection interval? If for example there are 6 packets in ATT table they will be transmitted in the same next connection interval?

BLE_GATTS_EVT_HVN_TX_COMPLETE event occurs when a packet has been sent over the link layer (notification transmission), meaning that the sd buffer has free space right?

If there is no acknowledgment from the Link Layer (BLE_GATTS_EVT_HVN_TX_COMPLETE event) the packet remains in sd buffer and re-transmitted?

Using notifications, you are allowing to queue a certain number of packets before sending them. If the tx buffer is full the sd_ble_gatts_hvx() will return the NRF_ERROR_RESOURCES error. In that case, you have to wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event meaning that the tx buffer has some free space right?

What is the reason that will cause sd buffers to get full and hence to return the NRF_ERROR_RESOURCES error?

Finally looking at the GATTS Handle Value Notification diagram I cannot understand in Variant#2 why only app_value_1 is transmitted.. I would expect both app_value_1 & 2 to be transmitted.

Also in Variant#1 of  GATTS Handle Value Notification diagram, when trying to add app_value_3 in ATT table, NRF_ERROR_RESOURCES returns, while after adding  app_value_4 it returns NRF_SUCCESS. I cannot understand this.. Could you please explain?

Thanks in advnace

Nick

Parents
  • Hi Nick, 

    There is a difference between "Att table" and the softdevice buffers. They are not the same. The softdevice buffers are the buffers for the out going packets, the notification packets for example. When the ATT table is the table that store the value of the attribute locally. They are not the same. For example in the Variant #1 case you pointed to, the sd_ble_gatts_hvx(app_value_3) returned ERR_RESOURCE (for some reasons, explained later) then that mean the notification for app_value_3 will not be queued, but the value in the att_table is still updated. 
    And then the next call for sd_ble_gatts_hvx(app_value_4) success and the notification packet will be queued, and the local att_table is updated. Only 3 notification packets will be sent. 

    It's true that you can send 6 packets (or even more) in one connection interval, but there is no guarantee that you always can send 6 packets. If the event length is not configured long enough for such many packets, or if the peer device doesn't want to take multiple packet, you will have less. Also the buffer size can be 6 (or more) but it can be other activities that require some of the buffers. So you may have less number of the notification packet you can queue. 

    Even if a packet is queued, there is no guarantee that it will be sent in the next connection event. As I mentioned, the peer device may only accept 1 packet per connection event. This answer your question on why in variant #2 app_value_1 and app_value_2 is not sent at the same connection event. 

    When you receive BLE_GATTS_EVT_HVN_TX_COMPLETE () there is a chance that you can queue more packet, but it's not 100% sure you can, because there could be some other activity that already take the buffer (for example if you have other activity that add a write command, write command and notification send the same buffers). 

    So basically, what you do is to call sd_ble_gatts_hvx() until you receive NRF_ERROR_RESOURCES , then you wait for BLE_GATTS_EVT_HVN_TX_COMPLETE  event, and continue calling sd_ble_gatts_hvx(). You can read the value return in the  BLE_GATTS_EVT_HVN_TX_COMPLETE to know how many sd_ble_gatts_hvx() you should call. Or you can just simply call that function until you receive NRF_ERROR_RESOURCES.


Reply
  • Hi Nick, 

    There is a difference between "Att table" and the softdevice buffers. They are not the same. The softdevice buffers are the buffers for the out going packets, the notification packets for example. When the ATT table is the table that store the value of the attribute locally. They are not the same. For example in the Variant #1 case you pointed to, the sd_ble_gatts_hvx(app_value_3) returned ERR_RESOURCE (for some reasons, explained later) then that mean the notification for app_value_3 will not be queued, but the value in the att_table is still updated. 
    And then the next call for sd_ble_gatts_hvx(app_value_4) success and the notification packet will be queued, and the local att_table is updated. Only 3 notification packets will be sent. 

    It's true that you can send 6 packets (or even more) in one connection interval, but there is no guarantee that you always can send 6 packets. If the event length is not configured long enough for such many packets, or if the peer device doesn't want to take multiple packet, you will have less. Also the buffer size can be 6 (or more) but it can be other activities that require some of the buffers. So you may have less number of the notification packet you can queue. 

    Even if a packet is queued, there is no guarantee that it will be sent in the next connection event. As I mentioned, the peer device may only accept 1 packet per connection event. This answer your question on why in variant #2 app_value_1 and app_value_2 is not sent at the same connection event. 

    When you receive BLE_GATTS_EVT_HVN_TX_COMPLETE () there is a chance that you can queue more packet, but it's not 100% sure you can, because there could be some other activity that already take the buffer (for example if you have other activity that add a write command, write command and notification send the same buffers). 

    So basically, what you do is to call sd_ble_gatts_hvx() until you receive NRF_ERROR_RESOURCES , then you wait for BLE_GATTS_EVT_HVN_TX_COMPLETE  event, and continue calling sd_ble_gatts_hvx(). You can read the value return in the  BLE_GATTS_EVT_HVN_TX_COMPLETE to know how many sd_ble_gatts_hvx() you should call. Or you can just simply call that function until you receive NRF_ERROR_RESOURCES.


Children
  • Hi Hung and thank you for your answer!!

    The softdevice buffers are the buffers for the out going packets, the notification packets for example. When the ATT table is the table that store the value of the attribute locally

    I think that this is clear to me. So the sd buffer holds the packets that are going to be transmitted while the ATT table holds the information regarding the attributes (services, characteristics, descriptors) such as handle, UUID, and ATT value, right?

    So despite that sd_ble_gatts_hvx() may return NRF_ERROR_RESOURCES  the value of ATT table will be updated (I do not understand the reason behind that..). The ATT table value is updated for every sd_ble_gatts_hvx() call regardless if it was success or not?

    For example in the Variant #1 case you pointed to, the sd_ble_gatts_hvx(app_value_3) returned ERR_RESOURCE

    Meaning that the buffer was full at that specific moment in time due to other activities? So I believe that before buffering app_value_4 a  BLE_GATTS_EVT_HVN_TX_COMPLETE event had preceded right?

    So basically, what you do is to call sd_ble_gatts_hvx() until you receive NRF_ERROR_RESOURCES , then you wait for BLE_GATTS_EVT_HVN_TX_COMPLETE  event, and continue calling sd_ble_gatts_hvx()

    Something like that?

    #define QUEUE_SIZE 4
    
    
    // after the app_timer expire buffer 4 notifications
    for (uint8_t i = 0; i < QUEUE_SIZE; i++) {
    
      error_code = sd_ble_gatts_hvx();
      // error filtering
      if (error_code != NRF_ERROR_RESOURCES) {
        APP_ERROR_CHECK(error_code);
      }
    }

    You can read the value return in the  BLE_GATTS_EVT_HVN_TX_COMPLETE to know how many sd_ble_gatts_hvx() you should call.

    The return value is the number of packets was sent in the same connection event?

    Thanks

    Nick

  • Nikosant03 said:
    So the sd buffer holds the packets that are going to be transmitted while the ATT table holds the information regarding the attributes (services, characteristics, descriptors) such as handle, UUID, and ATT value, right?

     ==> Correct 

     

    Nikosant03 said:
    So despite that sd_ble_gatts_hvx() may return NRF_ERROR_RESOURCES  the value of ATT table will be updated (I do not understand the reason behind that..). The ATT table value is updated for every sd_ble_gatts_hvx() call regardless if it was success or not?

    ==> Correct, please check the description of sd_ble_gatts_hvx() function in ble_gatts.h

     

    Nikosant03 said:
    Meaning that the buffer was full at that specific moment in time due to other activities? So I believe that before buffering app_value_4 a  BLE_GATTS_EVT_HVN_TX_COMPLETE event had preceded right?

     ==> Yes. It could be a write command has been executed. or a notification previously queued now sent. 

     

    Nikosant03 said:
    Something like that?

     In the code, you can just break after you receive NRF_ERROR_RESOURCES. After that you wait for BLE_GATTS_EVT_HVN_TX_COMPLETE . When you receive that event, you can call the loop again, or you can turn on a flag to continue the loop (of course you shouldn't wait infinitely in a loop wait for that event, should better put the CPU to sleep).

     

    Nikosant03 said:
    The return value is the number of packets was sent in the same connection event?

     ==> Correct, in the last connect event. 

  • Thank you Hung, now things are much more clear to me

     In the code, you can just break after you receive NRF_ERROR_RESOURCES. After that you wait for BLE_GATTS_EVT_HVN_TX_COMPLETE

    Using a timer something like that I believe should be fine right?

    I believe the reason that could cause the sd buffer to get full is in case that buffering happens faster than the packet transmission, right? So, what are the possible reasons that could cause the packet to not be transmitted and remain in the sd buffer causing high queuing and finally NRF_ERROR_RESOURCES?

Related