 Qs. Let's start from the Qs. So Qs are pipes. In fact, there are pipes to transfer the data between tasks in free R2S, in general. The transfer of the data can be done as well from interrupt to the Q. But in this case, please remember that the interrupt, which would operate on the Q, should have the correct priority number, not higher than specified as a max syscall within free R2S config.h file. By default, the Q is behaving as a FIFO, so first in, first out, and can be redefined to perform as last in, first out, a structure by using eqxq sent to front function. The problem is that this functionality is not available within CMC's R2S API. So in case you would need it within your implementation, please use free R2S API instead, which is much more flexible than CMC's R2S. All data sent by the Q must be the same type declared during Q creation phase. It can be a simple data variable like a jar integer long, or it can be a structure. Within CMC's R2S API, there are two types of the Qs. The message Q, where you can send only the integer data or a pointer or a structure, or mail, where you can send the memory blocks. We will focus within this training on this first type, so the message Q. Length of the Q is declared during creation phase and is defined as a number of items which will be sent via Q. Operations with the Qs are performed in a critical sections using base pre-register, so we are sure that none other tasks nor the interrupts which can perform any operations on the OS will be executed during the operations on the Q. Tasks can be blocked on operation on the Q, so on sending or receiving the data with a given timeout or infinitely. If we have multiple tasks which are blocked on waiting or for receiving or sending the data within the Q, the only task with the highest priority will be unlocked when the data will be available. So the first criteria to select the task which would cooperate with the Q is the priority. Highest priority task is always selected first. Then if we have all of the tasks with the same priority, the task that has been waiting for the longest time will be unlocked. Here we can see a typical use case of the Q. In this example we will have the following components. Q with length of four elements the same size, a sender task and a receiver task. At the beginning sender task is sending message 1 to the Q. Receiver is not yet requesting the data. In the next phase sender task is sending message 2 to the Q. After this we have two components in the Q. As it is a FIFO, so first in first out, message 1 will be read as a first one. In the third phase sender is not sending the data but receiver task gets one message from the Q. After this message 2 becomes a first component to be read and it is done in the fourth phase. In the fifth phase we have an empty Q and no activity neither on sender nor on receiver task. Let's have a look how we need to create the Q. So it is very similar to the tasks. So to create the Q we need to specify some attributes of it. So in this case it's much more simple because we are specifying only the Q name, in this case Q1, and then we are executing the function OSMessageQNew with three arguments. The first one is let's say the maximum number of the messages in the Q. Then we need to specify what is the message size in bytes. So it is the single component within the Q, its size. And then the third component is let's say the pointer to the attributes which is specified. So in this case it is the structure that contains the name and some other components which would be filled in during the creation of the Q. As a return of this function we are receiving the Q handle, start within the type OSMessageQID underscore t. If we will receive null it would mean that there is a problem with the creation of the Q and most probably we've got some issues with the memory allocation. So we need to verify whether there is enough memory space to allocate new resources. To delete the Q we need to execute the function OSMessageQDelete and the only argument is a Q handle which has been received during the creation of the Q. And the return value is OSStatus underscore t which informs us about the successfully or not operation of this deletion. So once it is OSOK it's 0. That means that everything went correctly and the Q has been deleted. Otherwise there were some issues with the operation. Let's have a look on two basic functions which can be used together with the Qs. The functions to put and receive the data to and from the Q. To put the data into the Q we've got a dedicated function OSMessageQPut. It is in fact calling QXQSend within 3R2S API. This function requires four arguments. The first one is a handle to the Q. The second one is a pointer to the buffer of the message which we would like to send into the Q. Then there is a message priority which is not used within the current implementation. And the last one is a timeout in milliseconds to wait till operation will be completed. And here is the important message. If our function will be not successful so it will be not possible to put the data within the given timeout the OSStatus underscore t returned value will be different from 0. It will be OSTimeout. So it is very important while coding the application with using OS functions to check the return value of the functions especially those OSStatus underscore t type. Because in this case we will have the information whether the function was successful or not. Okay, let's continue. So there is how to receive the data from the Q. For this we've got a dedicated function OSMessageQGet return value is exactly the same. So this is OSStatus underscore t type. And again we need four arguments. Starting from the Q handle. Then the pointer to the buffer for the message to get from the Q. Then the message priority which is not used and should be null. And at the end they are receiving timeout given in milliseconds. We've got some more functions which can operate on the Qs which is worth to know. So for example we've got a dedicated function to reset a message Q to initial empty state. For this we need to execute OSMessageQ reset. And as an argument we need to specify the Q handle. And the status of the operation is classical OSStatus underscore t. Then we can get the number of messages stored in the Q by calling the function OSMessageQ getCount. And again we need only the Q handle. And we can have the available space in the message Q. So for this we've got the function OSMessageQ getSpace. And again the only argument is a Q handle. So it can be useful in some particular cases when we would like to have more control on the Q which is operational for example by many tasks. Let's have a look on the Q parameters which are grouped within the structure of OSMessageQ 8tr underscore t defined within cmcs underscore os2.h file. We have seen this already within the creation of the Q. At that time we have specified within this structure only the name. And as you can see this is the only configurable part which is available within the Q by mix. And the rest of the attributes are set by the application after the creation of the Q. So from those we can see the attribute bits. Then we see the pointer to the Q control block area. Then we can see the control block size of the Q. Then we can see the pointer to the Q data storage area. So the storage on the objects of the data send via the Q and would be stored. And then we can see the size, the data size area of the Q. So those components are filled in by the code after the creation of the Q. We need to specify only the Q name. Here on the slide we can see the Q structure management. So in fact it is the control block of the Q. So it's similar to task control block but this one is in fact Q control block. It is defined within the Q.c file. And as you can see it has multiple fields starting from the pointer to the beginning of the Q storage area. Then we've got the pointer to the end in the Q storage area. So the head and tail like in the classical pipe. And then we've got some additional pointers which are reflecting the number of the three, let's say slots within the Q. Important message is within the frame where you can find let's say two lists. The first one is the list of let's say the tasks which are waiting to send data to the Q. It is stored in a priority order. And the second one is the list of the tasks that are blocked waiting to read from the Q. It is stored as well in a priority order. And based on these ones the Q can exchange the data of the task. Based on this list the selection is done. Which task can take the data or can send the data to the Q. Then we've got the number of the items currently stored within the Q. We've got the length of the Q defined as a number of items to be hold, not in a number of bytes. This is important. Then there is a size of the each item which is stored within the Q. This is very important. And the rest of the components are not that important. And the last three, please have a look, are related to the tracing possibility which is allowed within 3R2S. So once you use trace facility you have additionally Q number, Q type and some additional parameter which can be monitored within the debug session. So those would be assigned to Q and can be monitored within the debug session. So it can be helpful during the development phase. Here we can see some comparisons of Q functions across different APIs. Please notice that within 3R2S API we have much more possible options of data management within the Q. As you can see we have some options Q send to back, Q send to front, Q peak which means that we can have a look what is inside the Q without taking the data from it. It is not the case of CMC's OS API which contains much less functions on this. But what is positive within CMC's OS is that it is not necessary for us to pay attention which function we need to select once we call it from the task and which one once we call it from interrupt. The selection is done automatically within the function. It is defined within CMC's underscore OS dot C file. Thank you for watching this video.