 Now let's talk quickly about a native API. The native API is the original API created for the free RTOS. One remark, in the configuration, you can hide the native API if you want to use only the CMSIS-RTOS API. So the one compatible across different RTOSes. The native API still is underneath the CMSIS-RTOS implementation. So I recommend to keep the access here and time to time because CMSIS-RTOS standardizes the way how the RTOSes are used. It can miss some specific functionalities that are still available in the native API. So if you want to, you can use it. You can still include it in your application. The native API has got some conventions, like for variable names, it has got a prefix that shows what type of the variable it is. So whether its type is character, short, long, pointer, unsigned, specific return type. When we speak about functions, hey, again, it has got a prefix telling what return value it gives. So whether it doesn't give anything or a port-based type, specific type or return value, and whether the function is private or public. So this way you can very easily recognize what the function returns, what parameters it takes. Further, it gives you macros. These macros are constructed so that the first part of the macro defines the file where such macro is defined. So you can see that, for example, if it begins with a PD, it is defined in the project definitions. So you can very easily look for a specific set of values that are tied to this specific type. There are, as well, macro definitions for common return values and parameters, like true, false, pass, fail, so that you can test the functions for return values. On top of the native API, the free artist defines the CMSIS OS API. You know what the CMSIS OS API means. The CMSIS is a standard defined by ARM with a big help of ST, where ARM standardized the Cortex-M functionality, the macros and functions that help you to control any microcontroller based on the Cortex-M course. So the API was adapted by a lot of vendors, like our competitors. And there is, I think, more than 200 companies now implementing different Cortex-M microcontrollers. So a lot of them use the CMSIS as an interchangeable code. ARM realized that because there are a lot of ports of different real-time operating systems running on top of Cortex-M, they decided to standardize the API for the real-time operating systems, as well. So they created their own API that takes the common functions from these real-time operating systems and offered the API. First, it was implemented on top of the RTX, which is an in-house operating system created by Kyle, belonging to ARM now. Then it was implemented on the FreeRTOS. And it became a de facto standard for Cortex-M-based devices. It's as well very nice and easy to use. So it's a generic interface for Cortex-M-based processors. It uses as well some middleware components. But these are independent from RTOSs. And it allows easy transfer from one RTOS vendor to the other. It as well defines a minimum set of functionality, like management of the tasks, control of the kernel, semaphore, queue, and mail management, and the definition of the memory allocation and the allocation. When we work with the kubemix and our software stacks, we use this CMSIS-RTOS API by default so that if in future we decide to move to another RTOS, we can do it very easily. Now we can see the implementation in the CMSIS-OS.c file and where to find it. And you can see the examples of the differences between the native API of the free RTOS and the CMSIS-RTOS counterpart. One big advantage of the CMSIS-RTOS is that it's more readable. So you can see kernel start underneath the task start scheduler with a void return parameter. Thread create, x-task define, x-task create, or semaphore create. Here you can choose x-semaphore create binary or counting, and so on and so on. So the CMSIS-RTOS always begins with the OS and then the description of the function, which is, I would say, very nicely readable. The CMSIS-RTOS still uses underneath the original operating system. So it's a wrap-up layer, which means if you call the OS function, it will take all the parameters. It will make some security checks, for example. And then it will call the original function. So yes, a couple of clock cycles on top. On the other side, from programmer's point of view, it has a very good benefit because it standardizes functions. For example, the OS, for example, message put when you put some data into the queue of messages for a given task. If you operate in standard inter-task communication, you can call OS message put like it is. And you would as well call the same thing in the native API. But if you call this function from an interrupt, the situation changes. The CMSIS-RTOS will again use the OS message put function. So there is no change. And you don't care whether you are in interrupt or in a standard task. But for the native RTOS API, you need to call something like exMessageTransmitterSend from ISR. While the OS message put will look into the context of the processor, and it will decide whether it's in the interrupt or in the task. And it will choose the appropriate native function. So it makes your life easier, even if it costs you a little bit of clock cycles more. Most of the CMSIS-OS functions return the OS status value that you can check for OK, timeout, message received. So it's a different combination of return values and flags that can be tested. And it gives you quite a big control of what the system is doing. For example, if you don't implement memory overflow hook, when you request a new heap memory, new chunk of memory, the function will return a null pointer. And it will as well give you the return status that it failed. So if you test for the return status, you know that you should not proceed with your function because there is no memory allocated. That's where the OS status can be helpful. Additionally, each object that you create has got its own ID. And you can see the ID defined depending on the object used. So you can as well see that it's mapped to the original handle of the native RTOS. And I would say that it's effectively just a typecasted type. So it's very easy. If you take the OS semaphore ID and you simply pass it to the native function after typecasting, the delays in your application are given in milliseconds. And they have some special meanings or special values have special meanings. So null 0 means there is no delay. If you, for example, wait for a mutex, you define in a function how much time you want to spend waiting for the mutex. If you put 0, you only test if the mutex is available now and the function immediately returns whether the information mutex is there or not. So you don't wait for it. And I think bigger than 0 is a delay in milliseconds. And it's used for waiting for a specific time. However, there exists a special value called wait forever, OS wait forever. That's defined as minus 1 in 32 bits. And it defines infinite time. So if you don't want to define a time out but you still need to wait for something forever, this is the right macro or value to put into a function. And the task will get blocked without the timing mechanism. Now let's look at the OS status values. You can see that when everything goes well, it returns OS OK with a value 0. So here it's not that if the function returns a positive value, it's fine. Here you have to test if the return parameter equals equals OS OK. Or we have got another thing. Like if you wait for a signal, you should check if the function returns the OS event signal or message or mail. But if it times out, it will give you an OS event time out. So typically you have to test what is the return value of a specific function and decide whether the result is positive. So you got some message or whether you got a time out. If we have got some errors, there are different things like additional errors defined. And you can see them listed here. So even errors have their own values. And you can see that if you test for the bit 7, you typically are able to recognize that the error came.