.. _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`.