blob: a378a8d2359f00bcae99f8b5e66e258e82d4c775 [file] [log] [blame]
.. _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.