| .. _microkernel_fifos: |
| |
| FIFOs |
| ##### |
| |
| Concepts |
| ******** |
| |
| The microkernel's FIFO object type is an implementation of a traditional |
| first in, first out queue. |
| |
| A FIFO allows tasks to asynchronously send and receive fixed-size data items. |
| Each FIFO has an associated ring buffer for holding data items that have been |
| sent but not yet received. |
| |
| Any number of FIFOs can be defined in a microkernel system. Each FIFO has a |
| name that uniquely identifies it. In addition, a FIFO defines the size of |
| the data items it handles and the maximum number of data items that can be |
| queued in its ring buffer, both of which must be greater than zero. |
| |
| A task sends a data item by specifying a pointer to an area containing the data |
| to be sent; the size of the data area must equal the FIFO's data item size. |
| The data is given directly to a receiving task (if one is waiting) or copied |
| to the FIFO's ring buffer (if space is available). When a FIFO is full |
| the sending task may choose to wait for space to become available. |
| |
| Any number of tasks may wait on a full FIFO simultaneously; when space for |
| a data item becomes available it is given to the highest priority task that |
| has waited the longest. |
| |
| A task receives a data item by specifying a pointer to an area to receive |
| the data; the size of the receiving area must equal the FIFO's data item size. |
| The data is copied from the FIFO's ring buffer (if it contains data items) |
| or taken directly from a sending task (if the FIFO is empty). When a FIFO |
| is empty the task may choose to wait for a data item to become available. |
| |
| Any number of tasks may wait on an empty FIFO simultaneously; when a data item |
| becomes available it is given to the highest priority task that has waited |
| the longest. |
| |
| Purpose |
| ******* |
| |
| Use a FIFO to transfer small data items between tasks in an asynchronous and |
| anonymous manner. |
| |
| .. note:: |
| A FIFO can be used to transfer large data items, if desired. However, |
| it is often preferable to send pointers to large data items to avoid |
| copying the data. The microkernel's memory map and memory pool object |
| types can be helpful for data transfers of this sort. |
| |
| A synchronous transfer can be achieved using the microkernel's mailbox |
| object type. |
| |
| A non-anonymous transfer can be achieved by having the sending task |
| embed its name in the data it sends, where it can be retrieved by |
| the receiving task. However, there is no straightforward way for the |
| sending task to determine the name of the task that received its data. |
| The microkernel's mailbox object type *does* support non-anonymous data |
| transfer. |
| |
| Usage |
| ***** |
| |
| Defining a FIFO |
| =============== |
| |
| The following parameters must be defined: |
| |
| *name* |
| This specifies a unique name for the FIFO. |
| |
| *depth* |
| This specifies the maximum number of data items |
| that can exist at any one time. |
| |
| *width* |
| This specifies the size (in bytes) of each data item. |
| |
| Public FIFO |
| ----------- |
| |
| Define the FIFO in the application's .MDEF file using the following syntax: |
| |
| .. code-block:: console |
| |
| FIFO name depth width |
| |
| For example, the file :file:`projName.mdef` defines a FIFO |
| that holds up to 10 items that are each 12 bytes long as follows: |
| |
| .. code-block:: console |
| |
| % FIFO NAME DEPTH WIDTH |
| % ============================= |
| FIFO SIGNAL_FIFO 10 12 |
| |
| A public FIFO can be referenced by name from any source file that includes |
| the file :file:`zephyr.h`. |
| |
| Private FIFO |
| ------------ |
| |
| Define the FIFO in a source file using the following syntax: |
| |
| .. code-block:: c |
| |
| DEFINE_FIFO(fifo_name, depth, width) |
| |
| For example, the following code defines a private FIFO named ``PRIV_FIFO``. |
| |
| .. code-block:: c |
| |
| DEFINE_FIFO(PRIV_FIFO, 10, 12); |
| |
| To utilize this FIFO from a different source file use the following syntax: |
| |
| .. code-block:: c |
| |
| extern const kfifo_t PRIV_FIFO; |
| |
| Example: Writing to a FIFO |
| ========================== |
| |
| This code uses a FIFO to pass data items from a producing task to |
| one or more consuming tasks. If the FIFO fills up because the consumers |
| can't keep up, throw away all existing data so newer data can be saved. |
| |
| .. code-block:: c |
| |
| void producer_task(void) |
| { |
| struct data_item_t data; |
| |
| while (1) { |
| /* create data item to send (e.g. measurement, timestamp, ...) */ |
| data = ... |
| |
| /* send data to consumers */ |
| while (task_fifo_put(SIGNAL_FIFO, &data, TICKS_NONE) != RC_OK) { |
| /* FIFO is full */ |
| task_fifo_purge(SIGNAL_FIFO); |
| } |
| |
| /* data item was successfully added to FIFO */ |
| } |
| } |
| |
| Example: Reading from a FIFO |
| ============================ |
| |
| This code uses a FIFO to process data items from generated by |
| one or more producing tasks. |
| |
| .. code-block:: c |
| |
| void consumer_task(void) |
| { |
| struct data_item_t data; |
| |
| while (1) { |
| /* get a data item */ |
| task_fifo_get(SIGNAL_FIFO, &data, TICKS_UNLIMITED); |
| |
| /* process data item */ |
| ... |
| } |
| } |
| |
| APIs |
| **** |
| |
| The following APIs for a microkernel FIFO are provided by |
| :file:`microkernel.h`: |
| |
| :c:func:`task_fifo_put()` |
| Writes item to a FIFO, or wait for a specified time period if it is full. |
| |
| :c:func:`task_fifo_get()` |
| Reads item from a FIFO, or wait for a specified time period if it is empty. |
| |
| :c:func:`task_fifo_purge()` |
| Discards all items in a FIFO and unblock any tasks |
| waiting to read or write an item. |
| |
| :c:func:`task_fifo_size_get()` |
| Reads the number of items currently in a FIFO. |