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

Notification handling in pc-ble-driver vs on-chip handling

I've just found through some trial and error that SoftDevice (s130 at least) on the nRF51 DK handles a sequence of notifications in the following manner:

  1. call sd_ble_gatts_hvx() with the data to be notified
  2. if the call returns NRF_SUCCESS then send the next part of the data in the sequence
  3. each time you call the sd_ble_gatts_hvx() method with an NRF_SUCCESS increment a counter by one
  4. if one gets a BLE_ERROR_NO_TX_PACKETS then that attempt to send will have to be redone and one has to wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event before trying again.
  5. Meanwhile in the BLE_GATTS_EVT_HVN_TX_COMPLETE event handler decrement the counter by p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count given in the event
  6. When the counter decrements to 0 and there is no more to notify, you are done and can proceed to whatever you are doing next.

The interesting thing in this sequence, is that there is an asymmetry in the calls to sd_ble_gatts_hvx() and the number of BLE_GATTS_EVT_HVN_TX_COMPLETE events. All one can say is that the number of calls to sd_ble_gatts_hvx() >= BLE_GATTS_EVT_HVN_TX_COMPLETE.

Okay, that's fine and dandy for the on chip-code, but how does one do this in the pc-ble-driver? Does it work in the same way? Is there the same type of asymmetry where sd_ble_gatts_hvx() >= BLE_GATTS_EVT_HVN_TX_COMPLETE.? Since the pc-ble-driver does not support the sd_app_evt_wait() like it does in the on-chip version, I do not have the same control over the flow as I do on the chip so I have to come up with an equivalent.

For indications where there is a one-to-one relationship between calls and events, a semaphore is an easy and perfect solution. But notifications do not have that symmetry.

If I were to call a sem_wait() when I get a BLE_ERROR_NO_TX_PACKETS and then do a post_sem when I get enough BLE_GATTS_EVT_HVN_TX_COMPLETE events such that the counter is down to 0 would that work? Or are buffers available as soon as the first BLE_GATTS_EVT_HVN_TX_COMPLETE event is received even though the count value returned is only one? How much would it slow down the transfer by waiting for the count to decrement to 0 before calling the sem_post()?

For example say I make 6 calls to sd_ble_gatts_hvx() before I get BLE_ERROR_NO_TX_PACKETS. However, say I fot one BLE_GATTS_EVT_HVN_TX_COMPLETE event before I made my 6th call and got the NO_TX_PACKETs error, so counter is 5. At this point I do a sem_wait().

In the BLE_GATTS_EVT_HVN_TX_COMPLETE event handler should I wait for all events to be received (counter down to 0) before calling sem_post() to continue OR should I continue as soon as I get the first BLE_GATTS_EVT_HVN_TX_COMPLETE event? 

I do not know what is goin on under the hood so I have no idea how fast the  BLE_GATTS_EVT_HVN_TX_COMPLETE events come relative to the sd_ble_gatts_hvx() calls. Experience on the chip shows that events come with a noticeable delay. But I never had something big like a waveform where I may have to notify a sequence 1000 bytes in 20-byte hunks as fast as I can.

The selection of tags is missing pc-ble-driver. Doesn't that seem like a major miss?

Parents
  • Hi,

    If you want to transfer data using notification you should place new data in the tx buffer as soon as you receive the TX_complete event for as long as you have data to transfer. This should be done regardless of whether this is on chip or using the pc_ble driver. If you wait for the last buffer to be freed you will slow down transfer quite significantly as BLE uses lacy acknowledgement. This means the last packet sent by the peripheral in a connection event will not be acked in the same connection event. Instead it will only be acked (and the buffer freed) when the peripheral receives the first packet from the central in the sub subsequent connection event.

  • On chip I simply notify in a loop as long as I get success. I only wait on the event if I get the error message that I am out of TX buffers. This greatly speeds up transfers compared to indications where I need to wait for the peer confirmation event before sending the next one. Since the peer does not confirm notifications, the speedup is no surprise.

    I tried the same thing using the pc-ble-driver. Of course there are some differences. For one thing I use semaphores since there is no sd_app_evt_wait() support. Then with indications I simply do indications in a loop and repeat if I get an NRF_ERROR_BUSY.

    For notifications, I also repeat the loop and wait for a semaphore event only when I get the out of resources error. However, I did NOT get the big improvement over using indications instead as I did on chip. I noticed that the BLE_GATTS_EVT_HVN_TX_COMPLETE event was almost in step with the notification. I suppose the slowness is due to the overhead of going through the serial port meaning I never run out of buffers (never get the out of resources error); by the time I send the next buffer (even in a tight loop) the previous one has gone out the door.

Reply
  • On chip I simply notify in a loop as long as I get success. I only wait on the event if I get the error message that I am out of TX buffers. This greatly speeds up transfers compared to indications where I need to wait for the peer confirmation event before sending the next one. Since the peer does not confirm notifications, the speedup is no surprise.

    I tried the same thing using the pc-ble-driver. Of course there are some differences. For one thing I use semaphores since there is no sd_app_evt_wait() support. Then with indications I simply do indications in a loop and repeat if I get an NRF_ERROR_BUSY.

    For notifications, I also repeat the loop and wait for a semaphore event only when I get the out of resources error. However, I did NOT get the big improvement over using indications instead as I did on chip. I noticed that the BLE_GATTS_EVT_HVN_TX_COMPLETE event was almost in step with the notification. I suppose the slowness is due to the overhead of going through the serial port meaning I never run out of buffers (never get the out of resources error); by the time I send the next buffer (even in a tight loop) the previous one has gone out the door.

Children
  • brianreinhold said:
    I suppose the slowness is due to the overhead of going through the serial port meaning I never run out of buffers (never get the out of resources error); by the time I send the next buffer (even in a tight loop) the previous one has gone out the door

     Exactly. Not sure what throughput you are getting. But the serial interface will be the limiting factor eventually. I guess you could check your connection interval and how many packets you are able to send in each connection event using a sniffer if you want to try to maximize throughput as much as possible.

  • Not that critical - its good for design development and testing new protocols for health devices (which I am doing). But pay dirt is on a real chip. There the notifications are significantly faster.

Related