I have a task that goes into a loop and stays there until a flag is cleared. While in that loop, that task might receive various notifications. To avoid any of those notifications to be “carried out” after exiting the loop (at the next notification processing line later on) I use xTaskNotifyStateClear(). Again, that is to ensures that after coming out of that while loop the task has no notifications to process.
if the task receives many notifications while in that while loop (all to be ignored), do I have to call xTaskNotifyStateClear() multiple times until there are no notifications left?
if so do I only need to check that the return value is != pdTRUE to know that the notification queue is completely cleared?
There is an array of notification states, each of which can be pending or not pending, and an array of notification values, each of which is a 32-bit number (although you can interpret that number in different ways - as a count, or bit fields, or whatever). Each array position is independent so notifications don’t ‘queue’ up. If you call xTaskNotifyStateClear() it will clear the state of the notification at array index 0 to not pending. If you call xTaskNotifyStateClearIndexed() - then you can clear the notification state in any of the array index positions.
Likewise you can call ulTaskNotifyValueClear() or ulTaskNotifyValueClearIndexed() to set the 32-bit value to 0.
Thank you Richard,
my understanding is that notification states and notification values are mapped 1 to 1. i.e. each notification state has a corresponding notification value and vice-versa. But from reading your reply I think that might not be correct. Is it?
Also, regardless of the above point, what is the use of using/placing/reading notification at positions other than the one at index 0? I mean in a practical applications. Being new to RTOS I cannot think of the use for that.
Despite having read a lot I think I might still be confusing some basic concepts
There are a number of methods to communicate between tasks. Direct Task Notification is intended to be the lightest/fastest method so it does not have a queue. There may be times when multiple tasks need to to alert a single task so having multiple direct task notification channels satisfies those times. The original design had a single direct task notification so the legacy API just accesses channel 0.
As an example of a contrived use for multiple direct task notifications, imagine a task watchdog. In this situation a single task would monitor multiple tasks operation by checking for periodic direct task notifications. These periodic notifications would reset timers maintained by the watchdog task. If a notification was missed, the watchdog task could take action. By using multiple notification channels, it would be possible monitor many tasks independently. By using notifications this process can be kept very small and lightweight.
I think I am either missing some basic understanding or getting confused with terminology probably between message queues, notification buffers and notification arrays…
In my reply above I was asking about the 1:1 mapping of notifications states and values because read in the xTaskNotify() API page that “Each task has an array of ‘task notifications’ (or just ‘notifications’), each of which has a state and a 32-bit value.”
Is that different from queues and/or notification buffers?
I watched a few videos and also forum posts but still don’t understand or see any difference between a task having an array of notifications and a task having a queue? Could someone please explain difference in practice and when you use one or the other?
Richard mentioned that “Each array position is independent so notifications don’t ‘queue’ up.”. So how are they “removed” after being “read” (for example by a taskNotifyWait())?
And if they do not queue up, what is the sequence in which notifications are “read” (i.e. for example by a taskNotifyWait())?
Task notifications are essentially a set of configTASK_NOTIFICATION_ARRAY_ENTRIES variables that can be modified by any task (or interrupt). Each variable is independent of any other variables. If I set
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 4
Then I will have 4 notification variables in each task. The API for taskNotify allows you to read/write each variable independently and the value of a variable will simply be the last write to that variable. There is no queue so multiple writes to a single variable will overwrite each other.
There are other forms of inter-process communication. Queues for instance can have from 1 to N elements and writes to the queue will be stored sequentially and delivered to the receiving task one at a time with xQueueReceive(). If the queue has 1 unsigned long element then it operates very similarly to the task notify though it will only allow one write to the queue and will block a second write until the first data is read.
The notification arrays is a description of the task notification but it also describes how they are physically implemented. They are a set of 2 arrays, each array is configTASK_NOTIFICATION_ARRAY_ENTRIES long. One array contains the data data and the other array contains the current read/write status which will unblock a task.
Task Notification index 0 has special usage in stream & message buffers so it is best to avoid the use of index 0 if you are using these buffers. Stream & message buffers are an optimized method of sending either streams of unformatted bytes or messages (a fixed size block of data). The optimization for stream & message buffers is they can only have 1 writer and 1 reader. If multiple readers and writers are required then you must consider queues.
This is a long post, feel free to continue asking questions and we will be sure to sort out the confusion.
Thank you Joseph,
some things start getting clearer.
Also if I use buffers, if I understand you correctly I should avoid using xTaskNotify() and use xTaskNotifyIndexed() but not the case if I only use notifications correct?
If so the I assume that I would then have to use the notification index 1 to x instead of 0 to x-1. Correct?
What are the practical reasons of that preference and when should I use the 0-index notification?
In regards to why have an array now rather than a single one:
The original use cases for task notifications did not require them to maintain state across a function call. Indeed the stream and message buffer implementation uses task notifications itself - so when there was only a single notification then its state might change simply by using a stream buffer. Over time the notification scheme became very popular and developers started using them for all sorts of things, which meant the implementation had to be updated to enable state to be maintained across function calls. Introducing an array of task notifications (each array position has its own state and value and acts independently) made the notification much more flexible. For example, the stream buffer implementation still uses a task notification but it is known to use the notification at array position 0. If a user wants to maintain the state of a notification when using stream buffers they just have to use an array index other than 0.
As Richard said, if you want to use more than 1 notification with a task, you must use the xTaskNotifyIndexed(). Using a buffer + a notification counts as using 2 notifications requiring the use of the indexed version. In the case of using a buffer, notification 0 is reserved so yes, you would need to use index 1.
In general, I would define a constant for my notification channel.
#define myTaskNotificationChannel 0
and use that definition everywhere simply so I could change the channel easily if necessary and it will make my code easier to follow. For example:
#define LED_Notification_index 0
#define sensorReady_Notification_index 1
#define timeout_Notification_index 2
Thank you Richard and Joseph,
what do you mean by “…to enable state to be maintained across function calls.”? Do you mean when the context is switched to another task and then back? Or when a sub-function within that task is called and the use wants to access the state from that sub-function?
if I index a notification that is out of range (for example notification index 6 when configTASK_NOTIFICATION_ARRAY_ENTRIES is set to only 4) what happens and most importantly how can I test it to make sure that never happens? The return value of for example xTaskNotifyIndexed() is BaseType_t and does not provide any feedback on whether the index value passed was out of range.
I am not sure I understand what you mean by “channel” and the fact of changing it.
Thank you both again
The original notification was simply a notification without a data value to go with it. Sort of like a fast semaphore.
To answer the questions addressed to me:
There is a configASSERT defined at the beginning of each function to check the notification value against configTASK_NOTIFICATION_ARRAY_ENTRIES. Make sure you have defined configASSERT for your system so your code will do something appropriate should you encounter a problem. FreeRTOS - The Free RTOS configuration constants and configuration options - FREE Open Source RTOS for small real time embedded systems
sorry, by channel I meant the index of the notification. I should not have used imprecise language.