 Hello, let's do some basic exercise on queues. Okay, let's practice a bit. So we'll start the queue lab. We can reuse any of the previous labs where we've got two tasks. So in this case, we will need two tasks, but the naming will be a bit different than before. We will need task sender1 and the task receiver. Both tasks should have the same priority. Let's say OSPriorityNormal, we will have bit bigger stack size 256, and the entry functions would be the following. For the sender1, we will use start sender1 function. And for the receiver, we will use start receiver function. The rest of the parameters will keep as default. So this you can see it on the screen. In the same tab, task and queues, there is a space to specify the queues which we would like to have within our three-year task-based application. So bit below, within the queues area, we will just press add. Then within the new queue, we will specify the queue name to queue1, queue size to 8, and item size to unsigned int 8. So uint8 underscore t, allocation by default dynamic. Once done it, press OK, and we can regenerate the code by pressing Ctrl S with an STM32 cube IDE, or by pressing generate code with an STM32 cube mix. Once the code is generated, please open the main .c file, and let's have a look what has been generated by our code generator. So within the private variables, we can see three components. So two tasks, two handlers for the task. So sender1 handle, receiver handle, and we can see as well the handle for the queue1. So queue1 handle. Then within our code, after the initialization of the hardware, we can see the space with the creation of the queues. So we can see the specification of queue1 attributes, where we specify only the name, which we gave within our configurator queue1. And then within function OS message queue new, we are specifying as a first argument the queue size, so 8 components. Then we are specifying the queue item size. So in our case, this is adb.sign. With SF3rd argument, there is a pointer, let's say, at the address to the attributes table we just defined. Please remember that this queue1 underscore attributes contains much more information that only the name. It would contain as well the attributes for the queue, and it would contain information about the memory blocks which are assigned to this queue. So it's queueControlBlock, it's pointer beginning of the memory where this control block begins and its size. And the same story for the message storage area. So beginning of this area, the pointer to this area, and its size. Okay, after analysis of the code which has been generated by our tool for generating the code, let's do some code processing. So we will start from sender1 task function, so the function which should send something to the queue. So we will start with some variable declaration within the initialization part of the sender1 function. So just after user code begin5, we will declare adb value without sign x equal to 0. And then within the endless loop, we will start from task action. In this case, we'll try to send s as sender, and then just after it, we'll try to send some data into the queue. So we'll use always message queue put, then the first argument we'll use queue1 handle, so handler to the queue, then the item to be sent, so the address of our x variable, then the priority which is not used, and at the end the timeout given in milliseconds. Of course, it would be much better if I would use here either the infinite value, so always wait forever, for example, or if I would check at the end the status of this operation and in case if it's not always okay, do some other operations which would be a backup solution to, for example, send the data later on. Because one this operation will be not possible to be completed. One of the most common examples is that the queue is already full. In this case, always message queue put cannot be successful because there is no free space to be allocated for the new data which is sent by other tasks. In this case, we need to wait till any other task will recollect some data from the queue. In this case, it will give the space for the new data. So this is the very simplified, very optimistic version of the code. The best would be to use either infinite time as a timeout or to check the status and work differently if there would be something different than OS okay. This operation would be successful. I am increasing the X variable. In our case, this variable would be from 0 to 9. And then at the end, we are going into the blocked state for one second by calling OS delay function. So this is the code for our sender. Let's have a look on the receiver task. So receiver task is using start receiver function. And here again, we need to specify one local variable for this task. So when user code begins start receiver section, we will specify the unsigned 8-bit value called RES and initial value to 0. And then within the infinite loop, we will start from the task action. We will send in this case R from receiver. And then we will try to get the data from the queue. So we are using the function OS message queue get. Then the first argument is a queue handle. Then there is the address of the variable, which we would like to use as a storage area from the data from the queue. Then there is not used priority and the timeout. In this case, I used two seconds, so 2000 milliseconds, but again, better would be to use either the infinite time over here. So OS wait forever or to check the status of this operation. And in case it is not OS okay, perform a different action to repeat, for example, getting data from the queue. Usually we receive something which is not a correct execution of the, let's say, we are not able to get the data from the queue when the queue is empty. When the queue is empty, it is not possible to get anything from this. And we are waiting for the new data, which would be pulled by other tasks. Okay, so this is the ultra optimistic version. After this function, assuming that we collected something from the queue, we are calling the task action function. And we are transferring the data collected, it should be digit from 0 to 9. And I'm adding 48 just to have the ASCII codes of 0 to 9 digits. So we should have at the end 0 to 9 on the output of ITM. Then we can compile the project and start a debug session. And let's see what should be the final result. Let's see what is the final result on our output in my case it is SWV ITM data console. So I'm using the ITM to do this. It can be as well the USART, a simple communication. So what I can see is that the first one is a receiver who was trying to read something. It was not possible. And again, it would be much better to use some infinite timeout over here or to check this OS status. Then sender is going to the operation and it is sending 0 to the queue. It is in the next row received by the receiver. So I can see the 0 and receiver. So this is the second iteration of the task for reception. Sender is a sender, sender is sending 1 to the queue. And in the next row I can see that 1 is displayed by the receiver and r means that I'm waiting for the next data. And then sender, then in next row I can see 2 displayed by the receiver and r. And again sender, free end receiver and waiting for the next number and so on and so forth. So the 9 and then I'm starting from 0. Here we can see the example how we can make the more robust implementation of for example receiver task function. And here we can see that within the variables for the receiver task I added the new one. It is OS status underscore T type. This is r underscore state. And then I'm checking the return value of OS message queue get. This is r underscore state. Based on this information of this status I can perform different operation than going to the task action. If I do not receive anything I will not perform the task action in this case. And I have replaced the timeout into the OS wait forever. OS wait forever means that this function will wait continuously till the effect will be done. The problem is that if we are not sure that the data will come it will block us in this line forever. So it is better to monitor the state and in case the state is not OS okay perform different actions and unfreeze the task or in case we would like to freeze the task really and waiting for the queue we can use OS wait forever. But we should be aware that OS wait forever it is waiting and blocking our task on this particular line. And what is good is that what we can do next we can use this r underscore state and add it to the live view but for this it should be not local within the task but the global one and monitor it within the debug session. So it will be clearly visible when the queue will be empty and we cannot get any data out of this. Thank you for watching this video.