nRF51 SDK - S110 SoftDevice
|
The FIFO library provides a simple circular buffer implementation for storing bytes. The FIFO uses the size and buffer memory provided by the application on initialization.
The application must provide a FIFO structure and memory buffer to the initialization function.
The FIFO structured is passed by reference and will be initialized by the FIFO module.
As seen in the above code the application needs to ensure the buffer has reserved memory space for the lifetime of the FIFO.
The FIFO app_fifo_t instance will ensure correct indexing when reading and writing data to the FIFO.
The size of the buffer has to be a power of two.
The library module itself will not store state information thus the application must ensure that the memory used by app_fifo_t is not reclaimed as long as the FIFO is in use.
The structure used to make a FIFO instance contains 4 members:
The FIFO is implemented as a circular buffer of size <n>
. Whenever the <n>-th
element is added to the buffer, the index wraps over and counts from index zero.
This can be summarized to:
Thus we have: i = count mod n
.
To simplify the index handling, the FIFO is restricted to require the buffer size <n>
, to be a power of two, as this reduces the modulus operation to become a simple AND operation with
.<n>
- 1
Example, buffer size n = 8
:
n = 8 = 0b00001000 n - 1 = 7 = 0b00000111 ANDing any number with <n>-1 , is identical to the modulus operation of <n>, when <n> is a power of two, see below: 3 = 11 mod 8 = 11 AND 7 = 0b00001011 & 0b00000111 = 0b00000011 = 3 .
A check is performed during initialization of the FIFO to ensure the size <n>
is a power of two.
In the image below we can see a graphical representation of how the FIFO instance looks like when it is initialized. The two arrows on the top illustrates the read and write index to their next elements in the buffer. They both start at index 0 and all the bytes in the buffer is free to be used.
To add an element to the FIFO the application has to use the app_fifo_put function. This is done by passing the FIFO
structure
and the data
to app_fifo_put.
Example of adding an element to the FIFO:
When the new element is added to the buffer the value supplied as parameter to the put function will be copied over to the current index of the write_pos member of the FIFO instance. When an element has been added to the FIFO, the write_pos member of the instance will be incremented by 1 to point to the next free byte. This is illustrated in Figure 2. For each element added the write_pos counter increments. An illustration of this can be seen in Figure 3.
If the FIFO is full then NRF_ERROR_NO_MEM will be returned.
To get an element from the FIFO, the application has to use the app_fifo_get function.
This is done by passing the FIFO
structure
and a reference, return_val
, for returning the data from app_fifo_get.
Example of fetching an element from the FIFO:
When app_fifo_get is called the memory of the supplied by-reference parameter is filled with the value stored in the memory buffer. Then, the read_pos member of the FIFO instance is incremented to free the byte read. An example of a FIFO where two elements has been consumed is shown below in Figure 4. For each element fetched from the FIFO the read_pos counter is increment therefore each byte can only be fetched once. This is shown in Figure 4.
The read_pos and write_pos has the same value when the FIFO is empty. This is the case when the FIFO is initialized as read_pos and write_pos are both initialized to 0.
Or when all elements in the FIFO has been fetched, in which case read_pos == write_pos. An illustration of this is given in Figure 5.
The FIFO can also be emptied by executing app_fifo_flush.
When the FIFO is empty then any calls to app_fifo_get function will return NRF_ERROR_NOT_FOUND.
When write_pos == read_pos + <n>
then the buffer is full and any subsequent calls to app_fifo_put function will return NRF_ERROR_NO_MEM.