.. _building_lynx178:
Compiling the |me_h| Source for LynxOS-178
==========================================
Introduction
------------
|me| includes support for LynxOS-178 systems and enables |me| applications to
communicate using both UDP and the ARINC 653 transport. The support has been tested on the
POC-310 board with a LynxOS-178 system.
This manual explains how to configure and compile |me| to run on LynxOS-178
systems. |me| supports both POSIX and APEX APIs from LynxOS-178, and this documentation
considers both APIs.
- `LynxOS-178 POSIX Platform Notes`_
- `Compiling the libraries for LynxOS-178 POSIX`_
- `LynxOS-178 APEX Platform Notes`_
- `LynxOS-178 APEX Configuration`_
- `Compiling the libraries for LynxOS-178 APEX`_
- `Interoperability`_
LynxOS-178 POSIX Platform Notes
-------------------------------
|me| uses an abstract platform API that must be ported to different platforms.
This section discusses the implementation of the platform abstractions
on the LynxOS-178 POSIX platform.
.. contents::
:local:
Platform Initialization
.......................
Before any DDS entities are created, |me| must be initialized. This
initialization is done by first setting the OSAPI System property, and then
calling ``DDS_DomainParticipantFactory_get_instance()``.
Calling ``DDS_DomainParticipantFactory_get_instance()`` will automatically
initialize |me| using the OSAPI System property.
Heap
....
|me| will allocate all of its memory using `malloc`.
Mutex
.....
|me| uses recursive mutexes to protect its critical sections. Because all
|me| APIs are synchronous, a mutex `take` operation blocks until the mutex
becomes available. It is unexptected behavior if a mutex does not become
available.
Semaphores
..........
|me| uses a semaphore to implement the DDS WaitSet. One semaphore is
implemented with a condition variable while another semaphore is implemented
with an internal timer (e.g. a ``DDS_WaitSet`` with a finite duration) that
signals the condition variable upon timeout.
The resolution of a semaphore is rounded up to the nearest clock tick + 1.
Thus, a semaphore may take up to 2 clock ticks (at most) extra to time out.
The timeout is tied to the tick-time mentioned in :ref:`Timers`.
.. note::
|me| does not support multiple threads blocking on a semaphore. None of
the public |me| APIs would cause multiple threads to block on the same
semaphore.
Timers
......
|me| implements its own software timers to support timed events such as
periodic participant announcements and checking for missed deadlines.
The timer resolution for |me| timers is 10 milliseconds. This cannot
be changed without recompiling |me|.
|me| requires an external (to |me|) clock tick to run its internal timers.
On LynxOS-178, this clock tick is implemented with a dedicated thread.
This cannot be changed.
In addition to runnning the internal timers, |me| maintains an internal clock
that is started when |me| is first initialized, and which is incremented in each
clock-tick. The clock-tick is maintained as a 32-bit signed second counter and
a 32-bit unsigned nanosecond counter.
This internal clock is known as the "tick-time" and is a function of the number
of clock-ticks, not the actual time. The tick-time is used to control semaphore
timeout, deadline, and liveliness.
The timer subsystem is configured to use signals and semaphores to integrate
with the timer thread. This cannot be changed.
Time
....
DDS APIs use the time of day to timestamp samples. On LynxOS-178 systems, this
timestamp is retrieved using ``gettimeofday()``. Note that no check is performed
on the returned time of day (such as time going backwards).
The time is also used to determine the interval between two samples when
the sample ordering is per source timestamp on the *DataWriter*.
Threads
.......
|me| creates threads to run timers and process data received from the network.
By default, threads are created with the following:
- ``PTHREAD_EXPLICIT_SCHED`` attribute.
- ``PTHREAD_CREATE_DETACHED`` attribute.
- OS default stack size.
- Priority inheritied from spawning thread.
If the OSAPI_ThreadOptions ``OSAPI_THREAD_REALTIME_PRIORITY`` is used, the
following attributes are set as well:
- ``PTHREAD_SCOPE_SYSTEM``
- ``SCHED_FIFO``
Two types of thread priorties can be set:
- **Absolute**
A priority equal to or larger than zero is used as is, and must be within
the range allowed by the OS.
- **Calculated**
A priority between [``OSAPI_THREAD_PRIORITY_LOW``, ``OSAPI_THREAD_PRIORITY_HIGH``]
is calculated using the following formula:
::
OS.min_priority + (((OS.max_priority - OS.min_priority) * priority_level)/OSAPI_THREAD_PRIORITY_HIGH);
Sockets
.......
|me| creates a single socket to send data with and one socket for each
receive thread created. If a multicast address is specified to receive
data on, multicast loopback is automatically enabled.
System configuration
....................
More information can be found in the OS distribution documentation folder.
Compiling the libraries for LynxOS-178 POSIX
--------------------------------------------
This section explains how to compile the |me| source code for LynxOS-178 systems.
Compilation has to be done either using ``rtime-make``.
Compiling |me_h| with rtime-make
................................
The |me| source bundle includes a bash (on Linux and macOS systems) or BAT
(on Windows systems) script to simplify the invocation of CMake called
``rtime-make``. These scripts provide a convenient way to invoke CMake with the
correct options.
1. Make sure `CMake `_ is in the path.
2. Configure the build environment to setup an envvar ``PLATFORM_TOOLCHAIN_PATH``
that points to the Lynx MOSA.ic distribution root folder.
3. From the |me| install directory, call ``rtime-make`` with the ``--target``
option. For a list of available targets, use the ``--list`` option.
Please refer to :ref:`prepare` for details. For example,
to compile for x64:
.. code-block:: console
resource/scripts/rtime-make --target LynxOS-178 --name x64Lynx1782024.09.0.POSIXgcc11.3.0 --config Release --build
4. The |me| libraries will be available in:
::
/lib/x64Lynx1782024.09.0.POSIXgcc11.3.0
LynxOS-178 APEX Platform Notes
---------------------------------
|me| uses an abstract platform API that must be ported to different platforms.
This section discusses the implementation of the platform abstractions
on the LynxOS-178 APEX platform.
.. contents::
:local:
Platform Initialization
.......................
Before any DDS entities are created, |me| must be initialized. This
initialization is done by first setting the OSAPI System property, and then
calling ``DDS_DomainParticipantFactory_get_instance()``.
See `LynxOS-178 APEX Configuration`_ for how to configure the OSAPI System property.
This property cannot be reconfigured after |me| has been initialized.
Calling ``DDS_DomainParticipantFactory_get_instance()`` will automatically
initialize |me| using the OSAPI System property.
C API Restrictions
..................
The LynxOS-178 port of |me| implements platform abstractions using the ARINC
653 API. This API requires that all ARINC objects are created before entering
``NORMAL`` mode. Therefore, all DDS entities must be created before a partition
enters ``NORMAL`` mode.
The following C APIs can only be used before ``NORMAL`` mode:
- ``DDS_DomainParticipantFactory_get_instance``
- ``DDS_DomainParticipantFactory_create_participant``
- ``DDS_DomainParticipant_create_publisher``
- ``DDS_DomainParticipant_create_subscriber``
- ``DDS_DomainParticipant_create_topic``
- ``DDS_Publisher_create_datawriter``
- ``DDS_Subscriber_create_datareader``
- ``DDS_GuardCondition_new``
- ``DDS_WaitSet_new``
Heap
....
|me| can either allocate all of its memory using ``malloc`` or from a user provided
buffer. This behavior can be configured through the OSAPI System property. See
`LynxOS-178 APEX Configuration`_ for details on how to configure the heap.
Mutex
.....
|me| uses recursive mutexes to protect its critical sections. On LynxOS-178 systems,
mutexes are implemented using ARINC 653 semaphores. Because all |me| APIs are
synchronous, a mutex ``take`` operation blocks until the mutex becomes available.
It is unexpected behavior if a mutex does not become available.
Semaphores
..........
|me| uses semaphores to implement the DDS WaitSet. A DDS WaitSet with
a timeout calls ``WAIT_SEMAPHORE()`` with the timeout value directly, and
the timeout precision is determined by ``WAIT_SEMAPHORE()``.
.. note::
|me| does not support multiple threads blocking on a semaphore. None of
the public |me| APIs would cause multiple threads to block on the same
semaphore.
.. _Timers:
Timers
......
|me| implements its own software timers to support timed events such as
periodic participant announcements and checking for missed deadlines.
The timer resolution for |me| timers is equal to the period of the OSAPI
System timer thread. This thread can be configured through the
`OSAPI System Timer Thread Property`_.
In addition to running the internal timers, |me| maintains an internal clock
that is started when |me| is first initialized, and which is incremented in each
clock-tick. The clock-tick is maintained as a 32-bit signed second counter and
a 32-bit unsigned nanosecond counter.
This internal clock is known as the "tick-time" and is a function of the number
of clock-ticks, not the actual time. The tick-time is used to control semaphore
timeout, deadline, and liveliness.
For LynxOS-178 systems, the "tick-time" starts incrementing when the OSAPI System timer
thread first executes. The timer thread is implemented as an ARINC process which
will automatically start when the partition switches to ``NORMAL`` mode. The exact
timing for when this thread starts depends on the process's priority and the
on the other processes in the partition.
Time
....
DDS APIs use the system clock to timestamp samples. On LynxOS-178 systems, this
timestamp is retrieved using the ARINC 653 ``GET_TIME()`` API. Note that no
check is performed on the returned time (such as time going backwards).
The time is also used to determine the interval between two samples when
the sample ordering is per source timestamp on the *DataWriter*.
Threads
.......
|me| creates threads to run timers and process data received from the network.
On LynxOS-178 systems, threads are implemented using ARINC 653 processes.
ARINC 653 processes do not start executing until a partition enters ``NORMAL``
mode. Therefore, none of |me|'s internal threads will start executing until
``NORMAL`` mode.
By default, threads are created with:
- OS default stack size
- OS normal thread priority
- Period of ``INFINITE_TIME_VALUE``
- Time capacity of ``INFINITE_TIME_VALUE``
- ``SOFT`` deadline
- Empty process name
For LynxOS-178 systems, |me| defines the OS default stack size to be 128KB and OS
normal thread priority to be 98.
Sockets
.......
|me| does not have access to datagram oriented communications when using APEX API.
For details on how to use the ARINC 653 transport, please refer to the
:ref:`arinc653_transport` documentation.
LynxOS-178 APEX Configuration
--------------------------------
The OSAPI System Property must be set before any other call to a |me| API.
This is done by using ``OSAPI_System_get_property()`` to get the property, then
making the necessary changes, and finally setting the property with
``OSAPI_System_set_property()``.
.. code-block:: c
/* Example application configuration of OSAPI System Property */
struct OSAPI_SystemProperty osapi_sys_prop;
/* Get the OSAPI_SystemProperty */
if (!OSAPI_System_get_property(&osapi_sys_prop))
{
/* Handle failure condition */
}
/* Configure OSAPI System A653 Port Property */
osapi_sys_prop.port_property.parent.max_threads = 32;
/* Configure OSAPI System Lynx178 Port Property */
osapi_sys_prop.port_property.timer_resolution = 100;
/* Configure OSAPI System Timer Thread */
osapi_sys_prop.timer_property.thread.port_property.parent.period = INFINITE_TIME_VALUE;
osapi_sys_prop.timer_property.thread.port_property.parent.time_capacity= INFINITE_TIME_VALUE;
osapi_sys_prop.timer_property.thread.port_property.parent.deadline = SOFT;
osapi_sys_prop.timer_property.thread.stack_size = 32000;
osapi_sys_prop.timer_property.thread.priority = 99;
strcpy(osapi_sys_prop.timer_property.thread.port_property.parent.name, "rti.timer_thread");
if (!OSAPI_System_set_property(&osapi_sys_prop))
{
/* Handle failure condition */
}
OSAPI System Port Property
..........................
The OSAPI System Port Property defines parameters related to how resources are
pre-allocated for the ARINC 653 OSAPI implementation. If ``heap_base_address``
is ``NULL``, then |me| will allocate memory using ``malloc``. Optionally, an
application can allocate memory itself and give it to |me| by setting
``heap_base_address`` to be a pointer to the start of the buffer. If specifying
a ``heap_base_address``, the buffer's size must be defined in the port property
``heap_size``. If ``heap_base_address`` is ``NULL``, the value of ``heap_size```
is ignored. The maximum number of threads needs to be defined in ``max_threads``
so that memory can be allocated to store thread information.
Aside from that, |me| will need to be provided with the only LynxOS-178-specific
property, the timer resolution. The ARINC 653 system time will be based on the
LynxOS-178 high-resolution clock, that it is platform dependent and on most
boards will provide sub-micro second resolution. This value has to match the
number of nanoseconds it takes for the |me| internal software clock to tick.
This value will impact on the reliability of the library.
OSAPI System Timer Thread Property
..................................
|me| uses a timer thread to manage all the |me| timers, such as deadline
and liveliness timers. This thread must be run at a constant period. If the
thread period is set to ``INFINITE_TIME_VALUE``, then it will execute at the
configured timer resolution frequency. Note that the priority of this task
must be set based on the required system behavior.
Compiling the libraries for LynxOS-178 APEX
----------------------------------------------
This section explains how to compile the |me| source code for LynxOS-178.
Compilation has to be done either using ``rtime-make``.
Compiling |me_h| with rtime-make
................................
The |me| source bundle includes a bash (on Linux and macOS systems) or BAT
(on Windows systems) script to simplify the invocation of CMake called
``rtime-make``. These scripts provide a convenient way to invoke CMake with the
correct options.
1. Make sure `CMake `_ is in the path.
2. Configure the build environment to setup an envvar ``PLATFORM_TOOLCHAIN_PATH``
that points to the GHS OS and Compiler distribution root.
3. From the |me| install directory, call ``rtime-make`` with the ``--target``
option. For a list of available targets, use the ``--list`` option.
Please refer to :ref:`prepare` for details. For example,
to compile for the Kontron COMe-cTL6:
..code-block:: console
resource/scripts/rtime-make --target Lynx178 --name x64Lynx1782024.09.0.APEXgcc11.3.0 --config Release --build
4. The |me| libraries will be available in:
::
/lib/x64Lynx1782024.09.0.APEXgcc11.3.0
Interoperability
----------------
The |me| LynxOS-178 port does not have any additional restrictions regarding
interoperability; the same considerations apply as for other ports. For more
information, please refer to :ref:`section-micro_and_core`.