zephyr/doc/kernel/microkernel/microkernel_fifos.rst

194 lines
5.4 KiB
ReStructuredText

.. _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`
===========================================
:cpp:func:`task_fifo_put()`
Write item to a FIFO, or wait for a specified time period if the FIFO is
full.
:cpp: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.