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

How to send nRF8001 notifications

Hi, I have peripheral device using the nRF8001. I'm using the Android BLE SDK on the MCU to talk to it. I am having a problem where I am using lib_aci_set_local_data() SDK function and not receiving command responses for it once in a while. I think it is a "flow control" issue. I've read the user manual and searched these forums but can't figure out how to handle BLE "notifications" right.

So, I have some characteristics that are set up as notifications. The services.h file provides SET and TX pipes for each such characteristic. I also use other "write only" local data like BLE Device Information. And I use the Nordic UART Service. In general everything works great. It's just when too much happens at once I end up not receiving some command responses I expect.

The way I have coded the handling of notification characteristics is that I use lib_aci_set_local_data() with the SET pipe to set the local radio value for the characteristic and, if the lib_aci_is_pipe_available() function shows the characteristic TX pipe is open, I also use the lib_aci_send_data() function to send the data to the remote (central) device. Maybe I don't have to use both function calls? But, if not, why are there two pipes for the same characteristic.

I am also careful to try to follow the "flow control" rules. So I only do one system command at a time and I only do lib_aci_send_data() calls when there are data credits available. I also only do one lib_aci_set_local_data() call at a time. Since there are always a total of 2 data credits max with the nRF8001 I figure that means I never have more than 4 packets waiting to send to the radio. And the ACI library is set up with a queue length of 4 and, now that the official SDK uses the FIFO queuing scheme I proposed that allows all 4 packets to be used, the queue shouldn't overflow.

One thing I don't understand is whether there are other rules for flow control with setting local data? The SetLocalData radio command is listed as one of the "Data" commands. Does my code also need to check data credits before using that command and hold off until a credit is available? None of the examples really do that. In fact, I can't find any example that is real good about showing notifications at work.

Hopefully there is something I am doing wrong that someone can point out? Thanks. Fred

  • I have checked examples and found that the ble_heart_rate_template_with_battery_service example shows handling a notification characteristic in the battery.cpp file. It shows what I do. Meaning always using lib_aci_set_local_data() with the SET pipe and using lib_aci_send_data with the TX pipe if that pipe is available and there are credits available. The examples ignore return codes however and none of my code does. My code would throw an assertion if any lib_aci call fails or a pipe status event indicating errors is received.

    I also have the lib_aci debugging outputs enabled so I can see that the set_local_data and send commands get sent to the radio. It's just that the set_local_data command never gets the Command Response in the rare cases where lots of radio traffic is happening at the same time.

  • The "Set" Pipe is intended for peers that are polling the Characteristic by Reading. (i.e. Read Property) The "TX" Pipe is intended to update the Characteristic and send the Notifications. (Notify Property) If you are sending Notifications the "Set" operation is redundant, as the "TX" pipe will repeat the "Set" operation before sending the Notification.

    If a Characteristic has Read(Set Pipe) and Subscribed on the Notify (i.e TX Pipe Available), sending data on the TX pipe will suffice. If a Characteristic has Read and not Subscribed on Notify, setting the local data on the Set pipe will suffice.

    The Credit is for over the air transactions and not on the local ACI, so the operations on the local Characteristic will not consume any Credit.

  • As you point out you should use the pipe corresponding to the function you are calling. That is tx pipe for send data and set pipe for set data. Note that send data will update the value in the gattserver and notify the peer. So you don't need to call set local data as well. I assume you where updating the same characteristic value with both set data and send data? or did you perform these operations on different characteristics?

  • David, Great answer as always. Thanks. Now I get it about how to handle notifications right. But I still have the problem that I sometimes seem to lose the command response for the local data I send. I guess I'll just add a timeout handler and retry sending the local data if I don't get a response.

  • Hi Runar, Thanks for response. I was using set local data on the SET pipe and send data on the TX pipe for the same characteristic. I now understand that is redundant. And I will update my code to do one or the other (ie just write to the TX pipe when it's open and I have available credits to write with, use the SET pipe otherwise to just update the local server value). That will avoid 2 back-to-back operations so maybe will reduce chances of losing the command response for the local data. I am still just wondering if anyone has ever talked about radio problems (rev D) dropping responses in rare cases? Of course I know it could be problems with MCU SW or SPI comms issues or...

    I hope things will be better with timeout recovery I have added and not doing two transfers. Thank you. Fred

Related