| .. _microkernel_fifos: |
| |
| FIFOs |
| ##### |
| |
| Concepts |
| ******** |
| |
| The microkernel's :dfn:`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 used to hold data items that have been |
| sent but not yet received. |
| |
| Any number of FIFOs can be defined in a microkernel system. Each FIFO needs: |
| |
| * A **name** that uniquely identifies it. |
| * A **maximum quantity** of data items that can be queued in its ring buffer. |
| * The **data item size**, measured in bytes, of each data item it can handle. |
| |
| |
| 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 either 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 can 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, that space 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 by 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 :file:`.MDEF` file with 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 access 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 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 |
| **** |
| |
| FIFO APIs provided by :file:`microkernel.h` |
| =========================================== |
| |
| :c:func:`task_fifo_put()` |
| Write item to a FIFO, or wait for a specified time period if the FIFO is |
| full. |
| |
| :c:func:`task_fifo_get()` |
| Read item from a FIFO, or wait for a specified time period if the FIFO is |
| empty. |
| |
| :c:func:`task_fifo_purge()` |
| Discard all items in a FIFO and unblock any tasks waiting to read or write |
| an item. |
| |
| :c:func:`task_fifo_size_get()` |
| Read the number of items currently in a FIFO. |