194 lines
5.4 KiB
ReStructuredText
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.
|