Waiting for one of multiple notifications

Hi,
if I understand correctly, xTaskNotify() and xTaskNotifyGive() do exactly the same thing but the only difference is that xTaskNotify() has the additional advantage of setting some notification value/bits. i.e. xTaskNotify()is a superset of xTaskNotifyGive(). Correct?

If from a task I want to send a notification to another task as well as “pass” a value, then do I:

  • use lets say notification index 0 for all commands/notifications that don’t have any payload/value to be passed
  • reserve one notification index for each message that has a value. So that if I have 3 notifications that also need to pass the value then I would used index 1 to 3 for such notifications

Then in the standby task wait for the notification to do something depending on which one it is. Like this…:

Issuing task

.....
//send the notification to turn the motor on at index 0 because it is just a flag
vTaskNotify(xAPP_APPLY_Tasks, NOTIF_MOTOR_ON, eSetBits);
//set the value at notification index 1 (move clockwise 300 steps)
vTaskNotifyIndexed(1, xAPP_APPLY_Tasks, 300, eSetValueWithOverwrite);
//set the value at notification index 2 (move counterclockwise 2,000 steps)
vTaskNotifyIndexed(2, xAPP_APPLY_Tasks, 2,000, eSetValueWithOverwrite);
//set the value at notification index 3 (set torque to 5)
vTaskNotifyIndexed(2, xAPP_APPLY_Tasks, 5, eSetValueWithOverwrite);
....

But then, how do I wait for ANY of those tasks and then process only the one that arrived?

At the moment I have a xTaskNotifyWait() but that checks only index 0. I can use the Indexed version but then again that would only wait on a certain index and miss the others…
I thought of using ulTaskNotifyTakeIndexed() inside a loop going through the indexes 1 to 3 but that would keep returning the value that was set by the previous notification (or 0 if I cleared it previously).

What is the correct way to do it?

Also, is there a way to “peek” into the notifications to see if there is one pending but without processing it?

Thank you :slight_smile:

If I recall correctly xTaskNotifyGive() is a macro that calls xTaskNotify(). The xTaskNotifyGive() and ulTaskNotifyTake() functions are convenience functions (well, macros) provided to give an interface with similar semantics to the counting semaphore’s xSemaphoreGive() and xSemaphoreTake() API functions when the notification is used in place of counting semaphore.

If you want to pass a value then you would use the full interface rather than the mimicked-semaphore interface - namely xTaskNotify() and xTaskNotifyWait().

If the values are used serially, so all three values don’t need to persist at the same time, then you need not use three different indexes. You would only use more than one index if sending a notification to the same index would overwrite or loose information. For example, consider the oversimplified sequence:

AFunctionCallThatWaitsForANotificationValueAndUsesTheValueBeforeReturning();
AnotherFunctionThatDoesTheSame();

In this case the notification value received in the first function call is also consumed in the first function call, so the notification value received in the second function call can safely use the same notification index because the value received in the first function call is no longer needed. The same would be the case if the value received in the first function call was not consumed inside that function, but was consumed before the second function call.

Now consider the sequence:

Function1ReceivesANotificationValue();
Function2ReceivesANotificationValue();
Function3UsesTheValueReceivedByFunction1();

In this sequence the notification value received by Function1 is not consumed until Function3 - however another notification value was received by Function2 - so in between the first notification value being received and consumed. In this case, if Function2 is also to receive a value without corrupting the value consumed by Function3 it would have to use a different index in the array of task notifications.

There is no way to block on multiple notifications at the same time - although it would be interesting to add that ability into the code if it is useful.

Additionally - you could wait on multiple notifications if you did this as a two step process. For example, always block on the notification at index 0. Then, when a notification is sent to index 1, send a second notification to index 0 with the value 1. The receiving task would then block on index 0, receive the value 1, and know the value it is really interested in is at index 1, so it reads that one too.

Thank you Richard,
your second suggestion seems the preferred one with the current setup I have.

If I understand you correctly, this would then be the code…:

Issuing task:

.....
//send the notification to turn the motor on at index 0 because it is just a flag
vTaskNotify(xAPP_APPLY_Tasks, NOTIF_MOTOR_ON, eSetBits);
//send the notification to turn the motor on at index 0 because it is just a flag
vTaskNotify(xAPP_APPLY_Tasks, NOTIF_SET_TORQUE, eSetBits);
//**set the value to pass at index 1 because this is a value placed at index 1**
vTaskNotifyIndexed(1, xAPP_APPLY_Tasks, 300, eSetValueWithOverwrite);
....

Receiving task:

   ....
    if (xTaskNotifyWait(0, 0, &uiCurrentNotificationValue, portMAX_DELAY) == pdTRUE)
    {
         if ((uiCurrentNotificationValue & NOTIF_MOTOR_ON) != 0)
         {
               TurnMotorOn();
         }

         if ((uiCurrentNotificationValue & NOTIF_SET_TORQUE) != 0)
         {
               //retrieve torque value from index 1
               //uiTorqueValue = ulTaskNotifyTakeIndexed(1, 0);
               //SetTorque(uiTorqueValue);            
         }
    }
    ....

Correct?

Thank you :slight_smile:

Yes, you can use each of the notification bits as individual events as in your example.
But I’d set the ClearOnExit bitmap accordingly to clear the notification bits going to be handled in the following code to avoid spurious events e.g. if next time just NOTIF_MOTOR_ON is signaled the NOTIF_SET_TORQUE bit might be still set, if not cleared (OnExit)…

Thank you,
why on exit and not on entry? Clearing them on entry would it not allow a new notification to be set (almost like a 1-deep queue) while whatever you are doing for the first notification is being executed?

What are the pros and cons of each?

Thank you

OnEntry and/or OnExit depends on your actual use case.
Clearing OnExit allows to act on already pending notifications similar to waiting for an already signaled semaphore or a waiting for a message queue with pending messages.
Clearing OnEntry first resets the masked bits before waiting for new notifications which might be used to avoid dealing with meanwhile signaled notifications.

Thank you Hartmut :slight_smile: