diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst
index 68b02be23..820d3f854 100644
--- a/docs/CHANGELOG.rst
+++ b/docs/CHANGELOG.rst
@@ -6,6 +6,19 @@ All notable changes to the Vector SIL Kit project shall be documented in this fi
The format is based on `Keep a Changelog (http://keepachangelog.com/en/1.0.0/) `_.
+[4.0.45] - Unreleased
+---------------------
+
+Changed
+~~~~~~~
+
+- Add links to API sections in the documentation overview
+
+
+Added
+~~~~~
+
+- RPC usage example with lifecycle
[4.0.45] - UNRELEASED
---------------------
diff --git a/docs/api/can.rst b/docs/api/can.rst
index b045f7c62..1786b6da4 100644
--- a/docs/api/can.rst
+++ b/docs/api/can.rst
@@ -1,3 +1,5 @@
+.. _chap:can-service-api:
+
===================
CAN Service API
===================
diff --git a/docs/api/capi-lin.rst b/docs/api/capi-lin.rst
index ddf422f06..474b9c62e 100644
--- a/docs/api/capi-lin.rst
+++ b/docs/api/capi-lin.rst
@@ -1,87 +1,87 @@
-LIN C API
----------
-
-.. contents::
- :local:
- :depth: 3
-
-The LIN API for the C language provides communication in a LIN bus master/slave-architecture.
-The functionality is analogous to the C++ API described in :ref:`sec:lin`.
-
-LIN Controller
-~~~~~~~~~~~~~~
-
-**A LIN controller is created with the following function:**
-
-.. doxygenfunction:: SilKit_LinController_Create
-
-**A LIN controller's configuration is handed over to the function:**
-
-.. doxygenfunction:: SilKit_LinController_Init
-
-**The following set of functions can be used to add and remove event handlers on the controller:**
-
-.. doxygenfunction:: SilKit_LinController_AddFrameStatusHandler
-.. doxygenfunction:: SilKit_LinController_AddGoToSleepHandler
-.. doxygenfunction:: SilKit_LinController_AddWakeupHandler
-.. doxygenfunction:: SilKit_LinController_RemoveFrameStatusHandler
-.. doxygenfunction:: SilKit_LinController_RemoveGoToSleepHandler
-.. doxygenfunction:: SilKit_LinController_RemoveWakeupHandler
-
-**The following functions operate on a configured controller:**
-
-.. doxygenfunction:: SilKit_LinController_Status
-.. doxygenfunction:: SilKit_LinController_SetFrameResponse
-.. doxygenfunction:: SilKit_LinController_SendFrame
-.. doxygenfunction:: SilKit_LinController_SendFrameHeader
-.. doxygenfunction:: SilKit_LinController_GoToSleep
-.. doxygenfunction:: SilKit_LinController_GoToSleepInternal
-.. doxygenfunction:: SilKit_LinController_Wakeup
-.. doxygenfunction:: SilKit_LinController_WakeupInternal
-
-**The following functions are experimental and might be changed or removed in future versions:**
-
-.. doxygenfunction:: SilKit_Experimental_LinController_AddLinSlaveConfigurationHandler
-.. doxygenfunction:: SilKit_Experimental_LinController_RemoveLinSlaveConfigurationHandler
-.. doxygenfunction:: SilKit_Experimental_LinController_GetSlaveConfiguration
-
-Data Structures
-~~~~~~~~~~~~~~~
-.. doxygenstruct:: SilKit_LinControllerConfig
- :members:
-.. doxygenstruct:: SilKit_LinFrame
- :members:
-.. doxygenstruct:: SilKit_LinFrameResponse
- :members:
-.. doxygenstruct:: SilKit_Experimental_LinSlaveConfiguration
- :members:
-.. doxygenstruct:: SilKit_LinFrameStatusEvent
- :members:
-.. doxygenstruct:: SilKit_LinWakeupEvent
- :members:
-.. doxygenstruct:: SilKit_LinGoToSleepEvent
- :members:
-
-**The following data structures are experimental and might be changed or removed in future versions:**
-
-.. doxygenstruct:: SilKit_Experimental_LinSlaveConfigurationEvent
- :members:
-
-.. doxygentypedef:: SilKit_Experimental_LinSlaveConfigurationHandler_t
-
-Enumerations and Typedefs
-~~~~~~~~~~~~~~~~~~~~~~~~~
-.. doxygentypedef:: SilKit_LinController
-.. doxygentypedef:: SilKit_LinControllerStatus
-.. doxygentypedef:: SilKit_LinControllerMode
-.. doxygentypedef:: SilKit_LinBaudRate
-.. doxygentypedef:: SilKit_LinFrameResponseMode
-.. doxygentypedef:: SilKit_LinId
-.. doxygentypedef:: SilKit_LinChecksumModel
-.. doxygentypedef:: SilKit_LinFrameResponseType
-.. doxygentypedef:: SilKit_LinFrameStatus
-.. doxygentypedef:: SilKit_LinDataLength
-
-.. doxygentypedef:: SilKit_LinFrameStatusHandler_t
-.. doxygentypedef:: SilKit_LinGoToSleepHandler_t
-.. doxygentypedef:: SilKit_LinWakeupHandler_t
+LIN C API
+---------
+
+.. contents::
+ :local:
+ :depth: 3
+
+The LIN API for the C language provides communication in a LIN bus master/slave-architecture.
+The functionality is analogous to the C++ API described in :ref:`chap:lin-service-api`.
+
+LIN Controller
+~~~~~~~~~~~~~~
+
+**A LIN controller is created with the following function:**
+
+.. doxygenfunction:: SilKit_LinController_Create
+
+**A LIN controller's configuration is handed over to the function:**
+
+.. doxygenfunction:: SilKit_LinController_Init
+
+**The following set of functions can be used to add and remove event handlers on the controller:**
+
+.. doxygenfunction:: SilKit_LinController_AddFrameStatusHandler
+.. doxygenfunction:: SilKit_LinController_AddGoToSleepHandler
+.. doxygenfunction:: SilKit_LinController_AddWakeupHandler
+.. doxygenfunction:: SilKit_LinController_RemoveFrameStatusHandler
+.. doxygenfunction:: SilKit_LinController_RemoveGoToSleepHandler
+.. doxygenfunction:: SilKit_LinController_RemoveWakeupHandler
+
+**The following functions operate on a configured controller:**
+
+.. doxygenfunction:: SilKit_LinController_Status
+.. doxygenfunction:: SilKit_LinController_SetFrameResponse
+.. doxygenfunction:: SilKit_LinController_SendFrame
+.. doxygenfunction:: SilKit_LinController_SendFrameHeader
+.. doxygenfunction:: SilKit_LinController_GoToSleep
+.. doxygenfunction:: SilKit_LinController_GoToSleepInternal
+.. doxygenfunction:: SilKit_LinController_Wakeup
+.. doxygenfunction:: SilKit_LinController_WakeupInternal
+
+**The following functions are experimental and might be changed or removed in future versions:**
+
+.. doxygenfunction:: SilKit_Experimental_LinController_AddLinSlaveConfigurationHandler
+.. doxygenfunction:: SilKit_Experimental_LinController_RemoveLinSlaveConfigurationHandler
+.. doxygenfunction:: SilKit_Experimental_LinController_GetSlaveConfiguration
+
+Data Structures
+~~~~~~~~~~~~~~~
+.. doxygenstruct:: SilKit_LinControllerConfig
+ :members:
+.. doxygenstruct:: SilKit_LinFrame
+ :members:
+.. doxygenstruct:: SilKit_LinFrameResponse
+ :members:
+.. doxygenstruct:: SilKit_Experimental_LinSlaveConfiguration
+ :members:
+.. doxygenstruct:: SilKit_LinFrameStatusEvent
+ :members:
+.. doxygenstruct:: SilKit_LinWakeupEvent
+ :members:
+.. doxygenstruct:: SilKit_LinGoToSleepEvent
+ :members:
+
+**The following data structures are experimental and might be changed or removed in future versions:**
+
+.. doxygenstruct:: SilKit_Experimental_LinSlaveConfigurationEvent
+ :members:
+
+.. doxygentypedef:: SilKit_Experimental_LinSlaveConfigurationHandler_t
+
+Enumerations and Typedefs
+~~~~~~~~~~~~~~~~~~~~~~~~~
+.. doxygentypedef:: SilKit_LinController
+.. doxygentypedef:: SilKit_LinControllerStatus
+.. doxygentypedef:: SilKit_LinControllerMode
+.. doxygentypedef:: SilKit_LinBaudRate
+.. doxygentypedef:: SilKit_LinFrameResponseMode
+.. doxygentypedef:: SilKit_LinId
+.. doxygentypedef:: SilKit_LinChecksumModel
+.. doxygentypedef:: SilKit_LinFrameResponseType
+.. doxygentypedef:: SilKit_LinFrameStatus
+.. doxygentypedef:: SilKit_LinDataLength
+
+.. doxygentypedef:: SilKit_LinFrameStatusHandler_t
+.. doxygentypedef:: SilKit_LinGoToSleepHandler_t
+.. doxygentypedef:: SilKit_LinWakeupHandler_t
diff --git a/docs/api/ethernet.rst b/docs/api/ethernet.rst
index 158e900fe..a83571d56 100644
--- a/docs/api/ethernet.rst
+++ b/docs/api/ethernet.rst
@@ -1,242 +1,244 @@
-====================
-Ethernet Service API
-====================
-
-.. Macros for docs use
-.. |IParticipant| replace:: :cpp:class:`IParticipant`
-.. |CreateEthernetController| replace:: :cpp:func:`CreateEthernetController`
-.. |IEthernetController| replace:: :cpp:class:`IEthernetController`
-.. |Activate| replace:: :cpp:func:`Activate()`
-.. |SendFrame| replace:: :cpp:func:`SendFrame()`
-
-.. |AddFrameTransmitHandler| replace:: :cpp:func:`AddFrameTransmitHandler()`
-.. |AddStateChangeHandler| replace:: :cpp:func:`AddStateChangeHandler()`
-.. |AddFrameHandler| replace:: :cpp:func:`AddFrameHandler()`
-
-.. |RemoveFrameTransmitHandler| replace:: :cpp:func:`RemoveFrameTransmitHandler()`
-.. |RemoveStateChangeHandler| replace:: :cpp:func:`RemoveStateChangeHandler()`
-.. |RemoveFrameHandler| replace:: :cpp:func:`RemoveFrameHandler()`
-
-.. |EthernetFrame| replace:: :cpp:class:`EthernetFrame`
-.. |EthernetFrameEvent| replace:: :cpp:class:`EthernetFrameEvent`
-.. |EthernetFrameTransmitEvent| replace:: :cpp:class:`EthernetFrameTransmitEvent`
-.. |EthernetTransmitStatus| replace:: :cpp:enum:`EthernetTransmitStatus`
-
-.. |Transmitted| replace:: :cpp:enumerator:`EthernetTransmitStatus::Transmitted`
-.. |ControllerInactive| replace:: :cpp:enumerator:`EthernetTransmitStatus::ControllerInactive`
-.. |LinkDown| replace:: :cpp:enumerator:`EthernetTransmitStatus::LinkDown`
-.. |Dropped| replace:: :cpp:enumerator:`EthernetTransmitStatus::Dropped`
-.. |InvalidFrameFormat| replace:: :cpp:enumerator:`EthernetTransmitStatus::InvalidFrameFormat`
-
-.. |HandlerId| replace:: :cpp:class:`HandlerId`
-
-.. contents::
- :local:
- :depth: 3
-
-.. highlight:: cpp
-
-Using the Ethernet Controller
------------------------------
-
-The Ethernet Service API provides an Ethernet bus abstraction through the |IEthernetController| interface.
-An Ethernet controller is created by calling |CreateEthernetController| given a controller name and network
-name::
-
- auto* ethernetController = participant->CreateEthernetController("Eth1", "Eth");
-
-Ethernet controllers will only communicate within the same network.
-
-Initialization
-~~~~~~~~~~~~~~
-
-The Ethernet controller first has to call |Activate| before being able to
-send frames. Note that |Activate| can be called in the ``CommunicationReadyHandler`` of a ``LifecycleService``.
-
-
-Sending Ethernet Frames
-~~~~~~~~~~~~~~~~~~~~~~~
-
-An |EthernetFrame| is sent with |SendFrame| and received as an |EthernetFrameEvent|. The |EthernetFrame| must be setup
-according to layer 2 of IEEE 802.3, with
-
-- a source and destination MAC address (6 octets each),
-- an optional 802.1Q tag (4 octets),
-- the `EtherType` or length (Ethernet II or IEEE 802.3, 2 octets), and
-- the payload to be transmitted (46 octets or more).
-
-.. admonition:: Note
-
- The frame check sequence (32-bit CRC, 4 octets) is omitted. Thus, the minimum length of a frame is 60 octets.
-
-.. admonition:: Note
-
- If the frame is shorter than the minimum length of 60 octets, the frame will be padded with zeros to the minimum length.
-
-A valid frame can be setup and sent as follows::
-
- // Prepare an Ethernet frame
- const std::array destinationAddress{ 0xf6, 0x04, 0x68, 0x71, 0xaa, 0xc2 };
- const std::array sourceAddress{ 0xf6, 0x04, 0x68, 0x71, 0xaa, 0xc1 };
- const uint16_t etherType{ 0x0800 };
-
- const std::string message("Ensure that the payload is long enough to constitute"
- " a valid Ethernet frame ----------------------------");
- const std::vector payload{ message.begin(), message.end() };
-
- EthernetFrame frame{};
- std::copy(destinationAddress.begin(), destinationAddress.end(), std::back_inserter(frame.raw));
- std::copy(sourceAddress.begin(), sourceAddress.end(), std::back_inserter(frame.raw));
- auto etherTypeBytes = reinterpret_cast(ðerType);
- frame.raw.push_back(etherTypeBytes[1]); // We assume our platform to be little-endian
- frame.raw.push_back(etherTypeBytes[0]);
- std::copy(payload.begin(), payload.end(), std::back_inserter(frame.raw));
-
- ethernetController->SendFrame(frame);
-
-Transmission Acknowledgement
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To be notified of the success or failure of the transmission, a ``FrameTransmitHandler`` can be registered using
-|AddFrameTransmitHandler|::
-
- auto frameTransmitHandler = [](IEthernetController*, const EthernetFrameTransmitEvent& frameTransmitEvent)
- {
- // Handle frameTransmitEvent
- };
- ethernetController->AddFrameTransmitHandler(frameTransmitHandler);
-
-An optional second parameter of |AddFrameTransmitHandler| allows to specify the status (|Transmitted|, ...) of the
-|EthernetFrameTransmitEvent| to be received. By default, each status is enabled.
-
-.. admonition:: Note
-
- In a simple simulation, the |EthernetTransmitStatus| of the
- |EthernetFrameTransmitEvent| will always be |Transmitted|.
-
-Receiving Ethernet Frame Events
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-An |EthernetFrame| is received as an |EthernetFrameEvent| consisting of a ``transmitId`` used to identify
-the acknowledgement of the frame, a timestamp and the actual |EthernetFrame|.
-
-To receive Ethernet frames, a frame handler must be registered using |AddFrameHandler|. The handler is called whenever
-an Ethernet frame is received::
-
- auto frameHandler = [](IEthernetController*, const EthernetFrameEvent& frameEvent)
- {
- // Handle frameEvent
- };
- ethernetController->AddFrameHandler(frameHandler);
-
-An optional second parameter of |AddFrameHandler| allows to specify the direction (Tx, Rx, Tx/Rx) of the Ethernet frames to be
-received. By default, only frames of Rx direction are handled.
-
-Managing the Event Handlers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Adding a handler will return a |HandlerId| which can be used to remove the handler via:
-
-- |RemoveFrameHandler|
-- |RemoveFrameTransmitHandler|
-- |RemoveStateChangeHandler|
-
-Switches
-________
-
-Switches can be used in a detailed simulation.
-Refer to the documentation of the network simulator for further information.
-
-Receiving State Change Events
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To receive state changes of an Ethernet
-controller, a ``StateChangeHandler`` must be registered using |AddStateChangeHandler|::
-
- auto stateChangedHandler = [](IEthernetController*, const EthernetStateChangeEvent& stateChangeEvent)
- {
- // Handle stateChangeEvent;
- };
- ethernetController->AddStateChangeHandler(stateChangedHandler);
-
-Acknowledgements
-~~~~~~~~~~~~~~~~
-
-When sending frames, the |EthernetTransmitStatus| of the |EthernetFrameTransmitEvent| received in the
-``FrameTransmitHandler`` will be one of the following values:
-
-- |Transmitted|: Transmission was successful.
-- |ControllerInactive|: The sending Ethernet controller tried to send a frame before |Activate| was called.
-- |LinkDown|: |Activate| has been called but the link to another Ethernet Controller has not yet been established.
-- |Dropped|: Indicates a transmit queue overflow.
-- |InvalidFrameFormat|: The Ethernet frame is invalid, e.g., too small or too large.
-
-API and Data Type Reference
----------------------------
-
-Ethernet Controller API
-~~~~~~~~~~~~~~~~~~~~~~~
-
-.. doxygenclass:: SilKit::Services::Ethernet::IEthernetController
- :members:
-
-Data Structures
-~~~~~~~~~~~~~~~
-
-.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrame
- :members:
-.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrameEvent
- :members:
-.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrameTransmitEvent
- :members:
-.. doxygenstruct:: SilKit::Services::Ethernet::EthernetStateChangeEvent
- :members:
-.. doxygenstruct:: SilKit::Services::Ethernet::EthernetBitrateChangeEvent
- :members:
-
-Enumerations and Typedefs
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. doxygentypedef:: SilKit::Services::Ethernet::EthernetBitrate
-.. doxygenenum:: SilKit::Services::Ethernet::EthernetTransmitStatus
-.. doxygenenum:: SilKit::Services::Ethernet::EthernetState
-
-Usage Examples
---------------
-
-This section contains complete examples that show the usage and the interaction of two Ethernet controllers. Although
-the Ethernet controllers would typically belong to different participants and reside in different processes, their
-interaction is shown sequentially to demonstrate cause and effect.
-
-Assumptions:
-
-- Variables ``ethernetReceiver``, ``ethernetSender`` are of type |IEthernetController|.
-- All Ethernet controllers are connected to the same switch.
-
-Simple Ethernet Sender / Receiver Example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows a successful data transfer from one Ethernet controller to another.
-
-.. literalinclude::
- examples/eth/ETH_Sender_Receiver.cpp
- :language: cpp
-
-State Transition Example
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows the possible state transitions for an Ethernet controller.
-
-.. literalinclude::
- examples/eth/ETH_State_Transitions.cpp
- :language: cpp
-
-
-Erroneous Transmissions (Detailed Simulation only)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows different possible erroneous Ethernet transmissions.
-
-.. literalinclude::
- examples/eth/ETH_Erroneous_Transmissions.cpp
- :language: cpp
+.. _chap:ethernet-service-api:
+
+====================
+Ethernet Service API
+====================
+
+.. Macros for docs use
+.. |IParticipant| replace:: :cpp:class:`IParticipant`
+.. |CreateEthernetController| replace:: :cpp:func:`CreateEthernetController`
+.. |IEthernetController| replace:: :cpp:class:`IEthernetController`
+.. |Activate| replace:: :cpp:func:`Activate()`
+.. |SendFrame| replace:: :cpp:func:`SendFrame()`
+
+.. |AddFrameTransmitHandler| replace:: :cpp:func:`AddFrameTransmitHandler()`
+.. |AddStateChangeHandler| replace:: :cpp:func:`AddStateChangeHandler()`
+.. |AddFrameHandler| replace:: :cpp:func:`AddFrameHandler()`
+
+.. |RemoveFrameTransmitHandler| replace:: :cpp:func:`RemoveFrameTransmitHandler()`
+.. |RemoveStateChangeHandler| replace:: :cpp:func:`RemoveStateChangeHandler()`
+.. |RemoveFrameHandler| replace:: :cpp:func:`RemoveFrameHandler()`
+
+.. |EthernetFrame| replace:: :cpp:class:`EthernetFrame`
+.. |EthernetFrameEvent| replace:: :cpp:class:`EthernetFrameEvent`
+.. |EthernetFrameTransmitEvent| replace:: :cpp:class:`EthernetFrameTransmitEvent`
+.. |EthernetTransmitStatus| replace:: :cpp:enum:`EthernetTransmitStatus`
+
+.. |Transmitted| replace:: :cpp:enumerator:`EthernetTransmitStatus::Transmitted`
+.. |ControllerInactive| replace:: :cpp:enumerator:`EthernetTransmitStatus::ControllerInactive`
+.. |LinkDown| replace:: :cpp:enumerator:`EthernetTransmitStatus::LinkDown`
+.. |Dropped| replace:: :cpp:enumerator:`EthernetTransmitStatus::Dropped`
+.. |InvalidFrameFormat| replace:: :cpp:enumerator:`EthernetTransmitStatus::InvalidFrameFormat`
+
+.. |HandlerId| replace:: :cpp:class:`HandlerId`
+
+.. contents::
+ :local:
+ :depth: 3
+
+.. highlight:: cpp
+
+Using the Ethernet Controller
+-----------------------------
+
+The Ethernet Service API provides an Ethernet bus abstraction through the |IEthernetController| interface.
+An Ethernet controller is created by calling |CreateEthernetController| given a controller name and network
+name::
+
+ auto* ethernetController = participant->CreateEthernetController("Eth1", "Eth");
+
+Ethernet controllers will only communicate within the same network.
+
+Initialization
+~~~~~~~~~~~~~~
+
+The Ethernet controller first has to call |Activate| before being able to
+send frames. Note that |Activate| can be called in the ``CommunicationReadyHandler`` of a ``LifecycleService``.
+
+
+Sending Ethernet Frames
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An |EthernetFrame| is sent with |SendFrame| and received as an |EthernetFrameEvent|. The |EthernetFrame| must be setup
+according to layer 2 of IEEE 802.3, with
+
+- a source and destination MAC address (6 octets each),
+- an optional 802.1Q tag (4 octets),
+- the `EtherType` or length (Ethernet II or IEEE 802.3, 2 octets), and
+- the payload to be transmitted (46 octets or more).
+
+.. admonition:: Note
+
+ The frame check sequence (32-bit CRC, 4 octets) is omitted. Thus, the minimum length of a frame is 60 octets.
+
+.. admonition:: Note
+
+ If the frame is shorter than the minimum length of 60 octets, the frame will be padded with zeros to the minimum length.
+
+A valid frame can be setup and sent as follows::
+
+ // Prepare an Ethernet frame
+ const std::array destinationAddress{ 0xf6, 0x04, 0x68, 0x71, 0xaa, 0xc2 };
+ const std::array sourceAddress{ 0xf6, 0x04, 0x68, 0x71, 0xaa, 0xc1 };
+ const uint16_t etherType{ 0x0800 };
+
+ const std::string message("Ensure that the payload is long enough to constitute"
+ " a valid Ethernet frame ----------------------------");
+ const std::vector payload{ message.begin(), message.end() };
+
+ EthernetFrame frame{};
+ std::copy(destinationAddress.begin(), destinationAddress.end(), std::back_inserter(frame.raw));
+ std::copy(sourceAddress.begin(), sourceAddress.end(), std::back_inserter(frame.raw));
+ auto etherTypeBytes = reinterpret_cast(ðerType);
+ frame.raw.push_back(etherTypeBytes[1]); // We assume our platform to be little-endian
+ frame.raw.push_back(etherTypeBytes[0]);
+ std::copy(payload.begin(), payload.end(), std::back_inserter(frame.raw));
+
+ ethernetController->SendFrame(frame);
+
+Transmission Acknowledgement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To be notified of the success or failure of the transmission, a ``FrameTransmitHandler`` can be registered using
+|AddFrameTransmitHandler|::
+
+ auto frameTransmitHandler = [](IEthernetController*, const EthernetFrameTransmitEvent& frameTransmitEvent)
+ {
+ // Handle frameTransmitEvent
+ };
+ ethernetController->AddFrameTransmitHandler(frameTransmitHandler);
+
+An optional second parameter of |AddFrameTransmitHandler| allows to specify the status (|Transmitted|, ...) of the
+|EthernetFrameTransmitEvent| to be received. By default, each status is enabled.
+
+.. admonition:: Note
+
+ In a simple simulation, the |EthernetTransmitStatus| of the
+ |EthernetFrameTransmitEvent| will always be |Transmitted|.
+
+Receiving Ethernet Frame Events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An |EthernetFrame| is received as an |EthernetFrameEvent| consisting of a ``transmitId`` used to identify
+the acknowledgement of the frame, a timestamp and the actual |EthernetFrame|.
+
+To receive Ethernet frames, a frame handler must be registered using |AddFrameHandler|. The handler is called whenever
+an Ethernet frame is received::
+
+ auto frameHandler = [](IEthernetController*, const EthernetFrameEvent& frameEvent)
+ {
+ // Handle frameEvent
+ };
+ ethernetController->AddFrameHandler(frameHandler);
+
+An optional second parameter of |AddFrameHandler| allows to specify the direction (Tx, Rx, Tx/Rx) of the Ethernet frames to be
+received. By default, only frames of Rx direction are handled.
+
+Managing the Event Handlers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Adding a handler will return a |HandlerId| which can be used to remove the handler via:
+
+- |RemoveFrameHandler|
+- |RemoveFrameTransmitHandler|
+- |RemoveStateChangeHandler|
+
+Switches
+________
+
+Switches can be used in a detailed simulation.
+Refer to the documentation of the network simulator for further information.
+
+Receiving State Change Events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To receive state changes of an Ethernet
+controller, a ``StateChangeHandler`` must be registered using |AddStateChangeHandler|::
+
+ auto stateChangedHandler = [](IEthernetController*, const EthernetStateChangeEvent& stateChangeEvent)
+ {
+ // Handle stateChangeEvent;
+ };
+ ethernetController->AddStateChangeHandler(stateChangedHandler);
+
+Acknowledgements
+~~~~~~~~~~~~~~~~
+
+When sending frames, the |EthernetTransmitStatus| of the |EthernetFrameTransmitEvent| received in the
+``FrameTransmitHandler`` will be one of the following values:
+
+- |Transmitted|: Transmission was successful.
+- |ControllerInactive|: The sending Ethernet controller tried to send a frame before |Activate| was called.
+- |LinkDown|: |Activate| has been called but the link to another Ethernet Controller has not yet been established.
+- |Dropped|: Indicates a transmit queue overflow.
+- |InvalidFrameFormat|: The Ethernet frame is invalid, e.g., too small or too large.
+
+API and Data Type Reference
+---------------------------
+
+Ethernet Controller API
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. doxygenclass:: SilKit::Services::Ethernet::IEthernetController
+ :members:
+
+Data Structures
+~~~~~~~~~~~~~~~
+
+.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrame
+ :members:
+.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrameEvent
+ :members:
+.. doxygenstruct:: SilKit::Services::Ethernet::EthernetFrameTransmitEvent
+ :members:
+.. doxygenstruct:: SilKit::Services::Ethernet::EthernetStateChangeEvent
+ :members:
+.. doxygenstruct:: SilKit::Services::Ethernet::EthernetBitrateChangeEvent
+ :members:
+
+Enumerations and Typedefs
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. doxygentypedef:: SilKit::Services::Ethernet::EthernetBitrate
+.. doxygenenum:: SilKit::Services::Ethernet::EthernetTransmitStatus
+.. doxygenenum:: SilKit::Services::Ethernet::EthernetState
+
+Usage Examples
+--------------
+
+This section contains complete examples that show the usage and the interaction of two Ethernet controllers. Although
+the Ethernet controllers would typically belong to different participants and reside in different processes, their
+interaction is shown sequentially to demonstrate cause and effect.
+
+Assumptions:
+
+- Variables ``ethernetReceiver``, ``ethernetSender`` are of type |IEthernetController|.
+- All Ethernet controllers are connected to the same switch.
+
+Simple Ethernet Sender / Receiver Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows a successful data transfer from one Ethernet controller to another.
+
+.. literalinclude::
+ examples/eth/ETH_Sender_Receiver.cpp
+ :language: cpp
+
+State Transition Example
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows the possible state transitions for an Ethernet controller.
+
+.. literalinclude::
+ examples/eth/ETH_State_Transitions.cpp
+ :language: cpp
+
+
+Erroneous Transmissions (Detailed Simulation only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows different possible erroneous Ethernet transmissions.
+
+.. literalinclude::
+ examples/eth/ETH_Erroneous_Transmissions.cpp
+ :language: cpp
diff --git a/docs/api/flexray.rst b/docs/api/flexray.rst
index c4c74e755..6100f3bec 100644
--- a/docs/api/flexray.rst
+++ b/docs/api/flexray.rst
@@ -1,3 +1,5 @@
+.. _chap:flexray-service-api:
+
===================
FlexRay Service API
===================
diff --git a/docs/api/lifecycleService.rst b/docs/api/lifecycleService.rst
index 826a64c0e..fcabf8173 100644
--- a/docs/api/lifecycleService.rst
+++ b/docs/api/lifecycleService.rst
@@ -1,241 +1,241 @@
-.. _sec:api-lifecycle-service:
-
-==================
-Lifecycle Service
-==================
-
-.. Macros for docs use
-
-.. |Participant| replace:: :doc:`Participant`
-.. |IParticipant| replace:: :cpp:class:`IParticipant`
-
-.. |ITimeSyncService| replace:: :cpp:class:`ITimeSyncService`
-
-.. |ILifecycleService| replace:: :cpp:class:`ILifecycleService`
-.. |StartLifecycle| replace:: :cpp:func:`StartLifecycle`
-.. |CreateTimeSyncService| replace:: :cpp:func:`CreateTimeSyncService`
-
-.. |SetWorkflowConfiguration| replace:: :cpp:func:`ISystemController::SetWorkflowConfiguration()`
-.. |AbortSimulation| replace:: :cpp:func:`ISystemController::AbortSimulation()`
-
-.. |Pause| replace:: :cpp:func:`Pause()`
-.. |Continue| replace:: :cpp:func:`Continue()`
-.. |Stop| replace:: :cpp:func:`Stop()`
-
-.. |ReportError| replace:: :cpp:func:`ReportError()`
-.. |State| replace:: :cpp:func:`State()`
-.. |Status| replace:: :cpp:func:`Status()`
-
-.. |CommunicationReadyHandler| replace:: :cpp:type:`CommunicationReadyHandler`
-
-.. |OperationMode| replace:: :cpp:enum:`OperationMode`
-.. |OperationMode_Coordinated| replace:: :cpp:enumerator:`OperationMode::Coordinated`
-.. |OperationMode_Autonomous| replace:: :cpp:enumerator:`OperationMode::Autonomous`
-
-.. |InvalidState| replace:: :cpp:enumerator:`Invalid`
-.. |ServicesCreatedState| replace:: :cpp:enumerator:`ServicesCreated`
-.. |CommunicationInitializingState| replace:: :cpp:enumerator:`CommunicationInitializing`
-.. |CommunicationInitializedState| replace:: :cpp:enumerator:`CommunicationInitialized`
-.. |ReadyToRunState| replace:: :cpp:enumerator:`ReadyToRun`
-.. |RunningState| replace:: :cpp:enumerator:`Running`
-.. |PausedState| replace:: :cpp:enumerator:`Paused`
-.. |StoppingState| replace:: :cpp:enumerator:`Stopping`
-.. |StoppedState| replace:: :cpp:enumerator:`Stopped`
-.. |ErrorState| replace:: :cpp:enumerator:`Error`
-.. |ShuttingDownState| replace:: :cpp:enumerator:`ShuttingDown`
-.. |ShutdownState| replace:: :cpp:enumerator:`Shutdown`
-.. |AbortingState| replace:: :cpp:enumerator:`Aborting`
-
-.. |IDataPublisher| replace:: :cpp:class:`IDataPublisher`
-.. |IDataSubscriber| replace:: :cpp:class:`IDataPublisher`
-.. |Publish| replace:: :cpp:func:`Publish()`
-
-.. contents::
- :local:
- :depth: 2
-
-.. highlight:: cpp
-
-The lifecycle service is used to orchestrate the workflow and states of a simulation participant.
-It provides access to the |ITimeSyncService|, registers callbacks for state changes, queries the participant's state and issues commands to change the state.
-For an overview of a participant's state and its relation to the simulation refer to the :ref:`participant lifecycle section`.
-
-.. _subsec:sim-configuring-lifecycle:
-
-Configuring the Lifecycle Service
----------------------------------
-
-To create the lifecycle service, a valid lifecycle configuration must be provided.
-Currently, only the mode that the lifecycle operates in can be configured.
-There are two possible operation modes:
-
-* Coordinated:
-
- * The lifecycle service will coordinate its state with other participants.
- It will do so by reacting to changes of the system state, which is based on the list of required participants.
- * A coordinated participant will only work, if any participant set a list of required participants as part of |SetWorkflowConfiguration|.
- * Coordinated participants will stop, as soon as the system state changes to the stopping state.
- * Coordinated participants can also be terminated externally using the |AbortSimulation| call.
-
-* Autonomous:
-
- * An autonomous participant will not align its state to the system state or any participant state of other participants.
- * The lifecycle service will run through all participant states until it is running, and it will trigger all callbacks.
- * Autonomous participants must stop themselves by explicitly calling |Stop|.
- * The only way to stop an autonomous participant externally is the |AbortSimulation| call.
-
-.. _subsec:sim-using-lifecycle:
-
-Using the Lifecycle Service
-----------------------------
-
-An |ILifecycleService| instance can be retrieved from a |Participant|.
-To do so, a lifecycle configuration must be provided::
-
- using SilKit::Services::Orchestration
- auto lifecycleConfig = LifecycleConfiguration{OperationMode::Coordinated};
- auto* lifecycleService = participant->CreateLifecycleService(lifecycleConfig);
-
-.. admonition:: Note
-
- Please note that the lifecycle service and the time synchronization service can only be created once.
- Calling these methods more than once throws an exception.
-
-Participants can synchronize their time with other participants (see :ref:`synchronized simulation run` for details)::
-
- auto* timeSyncService = lifecycleService->CreateTimeSyncService();
- (...)
- lifecycleService->StartLifecycle();
-
-Alternatively, participants can run asynchronously (regarding the time synchronization).
-This will happen if |CreateTimeSyncService| was not called before |StartLifecycle|.
-
-There are several callbacks, which are triggered on state transitions.
-They are always executed in the middleware's worker thread::
-
- lifecycleService->SetCommunicationReadyHandler(
- []() {
- std::cout << "Communication ready" << std::endl;
- }
- );
-
- lifecycleService->SetStopHandler(
- []() {
- std::cout << "Stopping" << std::endl;
- }
- );
-
- lifecycleService->SetShutdownHandler(
- []() {
- std::cout << "Shutting down" << std::endl;
- }
- );
-
- lifecycleService->SetAbortHandler(
- [](auto /*participantState*/) {
- std::cout << "Simulation is aborting" << std::endl;
- }
- );
-
-
-If a participant does not use the virtual time synchronization, a separate callback informs about the transition to the ``Running`` state.
-This can be used to start local timers::
-
- lifecycleService->SetStartingHandler(
- []() {
- std::cout << "Starting" << std::endl;
- }
- );
-
-The |CommunicationReadyHandler| should be used to initialize and configure :doc:`services and controllers`.
-
-Communication guarantees
-""""""""""""""""""""""""
-
-The following communication guarantees apply to participants that utilize a Lifecycle Service and are limited to RPC and Publish/Subscribe services.
-Bus systems have definitions on the protocol level for message acknowledgement.
-For RPC or Publish/Subscribe however, communication guarantees depend on the implementation.
-In the SIL Kit, the |CommunicationReadyHandler| handler is the first point at which guarantees can be given.
-This implies that |StartLifecycle| has already been called.
-Remote services that have been created at the point a participant calls |StartLifecycle| will be available for communication as soon as the |CommunicationReadyHandler| is triggered.
-As an example, a call to |Publish| on a |IDataPublisher| on participant A in the |CommunicationReadyHandler| is guaranteed to arrive at
-participant B if its |IDataSubscriber| has been created before participant A has called |StartLifecycle|.
-
-Communication in the |CommunicationReadyHandler| between participants that use the |OperationMode_Coordinated| is guaranteed.
-After |StartLifecycle| is called, these participants will wait for each other until all reached the |ServicesCreatedState| state.
-Therefore all services have already been created when the |CommunicationReadyHandler| is triggered.
-
-A common use-case where the guarantee also applies is described as follows: A participant with |OperationMode_Autonomous| wants to join an already running simulation.
-In this case, the services of the running participants have been created and the newly joining participant can communicate in the |CommunicationReadyHandler|.
-
-If several participants are defined with |OperationMode_Autonomous| and are executed 'simultaneously' in a distributed setup, their intention is to proceed through the lifecycle states without coordination.
-In this case, there is no deterministic execution order of controller creation and calls to |StartLifecycle| across the processes.
-Therefore, it is impossible to guarantee that a remote subscriber already exists at the time a participants tries to |Publish| in the |CommunicationReadyHandler|.
-Without the useage of a lifecycle, there is no way to synchronize controller creation across different participants.
-In other words, controllers can appear at any time and there is no call to the SIL Kit API to build up a communication guarantee on.
-In cases were such guarantees are indespensable, it is recommended to use a |ILifecycleService|.
-
-Note that a |IDataPublisher| can be defined with a history (of length 1).
-This guarantees the delivery of the last publication but is not coupled to the lifecycle states.
-
-Another guarantee can be given for communication in the SimulationStepHandler.
-All participants that take part in the distributed time algorithm are ready to exchange messages if the first SimulationStepHandler is triggered, regardless of their |OperationMode|.
-
-
-Controlling the Participant
-"""""""""""""""""""""""""""
-
-
-After a successful startup, the participant will enter the |RunningState| state.
-|State| returns the current state as a plain enumeration, whereas |Status| returns additional information such as the participant's name, the human-readable reason for entering the state, and the wall clock time when the state was entered.
-
-
-To temporarily pause a simulation task, the |Pause| method can be invoked with a human-readable explanation as a string argument.
-Execution can be resumed using the |Continue| method.
-
-
-To abort the simulation and report an error message, use the |ReportError| method.
-This will change the current participant state to the |ErrorState| state and report the error message to the SIL Kit runtime system.
-|ReportError| is also called when the invocation of a registered handler throws an exception.
-
-To stop a particular participant, use the |Stop| method.
-This will exit |RunningState| or |PausedState|, call the registered ``StopHandler`` (if it was set) and switch to the |StoppedState| state.
-Afterwards, the participant will shut down by first changing to the |ShuttingDownState| state, which triggers the shutdown handler (if it was set) and then finishing at the |ShutdownState| state.
-At this point, the future provided by |StartLifecycle| will return.
-
-API Reference
--------------
-
-.. doxygenclass:: SilKit::Services::Orchestration::ILifecycleService
- :members:
-
-Handlers
-""""""""
-
-.. doxygentypedef:: SilKit::Services::Orchestration::CommunicationReadyHandler
-.. doxygentypedef:: SilKit::Services::Orchestration::StartingHandler
-.. doxygentypedef:: SilKit::Services::Orchestration::StopHandler
-.. doxygentypedef:: SilKit::Services::Orchestration::ShutdownHandler
-.. doxygentypedef:: SilKit::Services::Orchestration::AbortHandler
-
-Data Structures
-"""""""""""""""
-
-.. doxygenstruct:: SilKit::Services::Orchestration::LifecycleConfiguration
-.. doxygenenum:: SilKit::Services::Orchestration::OperationMode
-
-.. doxygenstruct:: SilKit::Services::Orchestration::WorkflowConfiguration
-.. doxygenstruct:: SilKit::Services::Orchestration::ParticipantConnectionInformation
-
-Usage Example
---------------
-
-The following example is based on the ``SilKitCanDemo`` source code which is distributed with the SIL Kit, and slightly adapted for clarity.
-It demonstrates how to setup a lifecycle service and register callbacks to monitor participant state changes.
-
-To demonstrate how to properly initialize other services, a CAN controller is initialized within the ``CommunicationReady`` callback of the lifecycle service.
-This is the recommended way to set up controllers before first use.
-
-.. literalinclude::
- examples/sync/LifecycleNoSyncSample.cpp
- :language: cpp
+.. _chap:lifecycle-service-api:
+
+==================
+Lifecycle Service
+==================
+
+.. Macros for docs use
+
+.. |Participant| replace:: :doc:`Participant`
+.. |IParticipant| replace:: :cpp:class:`IParticipant`
+
+.. |ITimeSyncService| replace:: :cpp:class:`ITimeSyncService`
+
+.. |ILifecycleService| replace:: :cpp:class:`ILifecycleService`
+.. |StartLifecycle| replace:: :cpp:func:`StartLifecycle`
+.. |CreateTimeSyncService| replace:: :cpp:func:`CreateTimeSyncService`
+
+.. |SetWorkflowConfiguration| replace:: :cpp:func:`ISystemController::SetWorkflowConfiguration()`
+.. |AbortSimulation| replace:: :cpp:func:`ISystemController::AbortSimulation()`
+
+.. |Pause| replace:: :cpp:func:`Pause()`
+.. |Continue| replace:: :cpp:func:`Continue()`
+.. |Stop| replace:: :cpp:func:`Stop()`
+
+.. |ReportError| replace:: :cpp:func:`ReportError()`
+.. |State| replace:: :cpp:func:`State()`
+.. |Status| replace:: :cpp:func:`Status()`
+
+.. |CommunicationReadyHandler| replace:: :cpp:type:`CommunicationReadyHandler`
+
+.. |OperationMode| replace:: :cpp:enum:`OperationMode`
+.. |OperationMode_Coordinated| replace:: :cpp:enumerator:`OperationMode::Coordinated`
+.. |OperationMode_Autonomous| replace:: :cpp:enumerator:`OperationMode::Autonomous`
+
+.. |InvalidState| replace:: :cpp:enumerator:`Invalid`
+.. |ServicesCreatedState| replace:: :cpp:enumerator:`ServicesCreated`
+.. |CommunicationInitializingState| replace:: :cpp:enumerator:`CommunicationInitializing`
+.. |CommunicationInitializedState| replace:: :cpp:enumerator:`CommunicationInitialized`
+.. |ReadyToRunState| replace:: :cpp:enumerator:`ReadyToRun`
+.. |RunningState| replace:: :cpp:enumerator:`Running`
+.. |PausedState| replace:: :cpp:enumerator:`Paused`
+.. |StoppingState| replace:: :cpp:enumerator:`Stopping`
+.. |StoppedState| replace:: :cpp:enumerator:`Stopped`
+.. |ErrorState| replace:: :cpp:enumerator:`Error`
+.. |ShuttingDownState| replace:: :cpp:enumerator:`ShuttingDown`
+.. |ShutdownState| replace:: :cpp:enumerator:`Shutdown`
+.. |AbortingState| replace:: :cpp:enumerator:`Aborting`
+
+.. |IDataPublisher| replace:: :cpp:class:`IDataPublisher`
+.. |IDataSubscriber| replace:: :cpp:class:`IDataPublisher`
+.. |Publish| replace:: :cpp:func:`Publish()`
+
+.. contents::
+ :local:
+ :depth: 2
+
+.. highlight:: cpp
+
+The lifecycle service is used to orchestrate the workflow and states of a simulation participant.
+It provides access to the |ITimeSyncService|, registers callbacks for state changes, queries the participant's state and issues commands to change the state.
+For an overview of a participant's state and its relation to the simulation refer to the :ref:`participant lifecycle section`.
+
+.. _subsec:sim-configuring-lifecycle:
+
+Configuring the Lifecycle Service
+---------------------------------
+
+To create the lifecycle service, a valid lifecycle configuration must be provided.
+Currently, only the mode that the lifecycle operates in can be configured.
+There are two possible operation modes:
+
+* Coordinated:
+
+ * The lifecycle service will coordinate its state with other participants.
+ It will do so by reacting to changes of the system state, which is based on the list of required participants.
+ * A coordinated participant will only work, if any participant set a list of required participants as part of |SetWorkflowConfiguration|.
+ * Coordinated participants will stop, as soon as the system state changes to the stopping state.
+ * Coordinated participants can also be terminated externally using the |AbortSimulation| call.
+
+* Autonomous:
+
+ * An autonomous participant will not align its state to the system state or any participant state of other participants.
+ * The lifecycle service will run through all participant states until it is running, and it will trigger all callbacks.
+ * Autonomous participants must stop themselves by explicitly calling |Stop|.
+ * The only way to stop an autonomous participant externally is the |AbortSimulation| call.
+
+.. _subsec:sim-using-lifecycle:
+
+Using the Lifecycle Service
+----------------------------
+
+An |ILifecycleService| instance can be retrieved from a |Participant|.
+To do so, a lifecycle configuration must be provided::
+
+ using SilKit::Services::Orchestration
+ auto lifecycleConfig = LifecycleConfiguration{OperationMode::Coordinated};
+ auto* lifecycleService = participant->CreateLifecycleService(lifecycleConfig);
+
+.. admonition:: Note
+
+ Please note that the lifecycle service and the time synchronization service can only be created once.
+ Calling these methods more than once throws an exception.
+
+Participants can synchronize their time with other participants (see :ref:`synchronized simulation run` for details)::
+
+ auto* timeSyncService = lifecycleService->CreateTimeSyncService();
+ (...)
+ lifecycleService->StartLifecycle();
+
+Alternatively, participants can run asynchronously (regarding the time synchronization).
+This will happen if |CreateTimeSyncService| was not called before |StartLifecycle|.
+
+There are several callbacks, which are triggered on state transitions.
+They are always executed in the middleware's worker thread::
+
+ lifecycleService->SetCommunicationReadyHandler(
+ []() {
+ std::cout << "Communication ready" << std::endl;
+ }
+ );
+
+ lifecycleService->SetStopHandler(
+ []() {
+ std::cout << "Stopping" << std::endl;
+ }
+ );
+
+ lifecycleService->SetShutdownHandler(
+ []() {
+ std::cout << "Shutting down" << std::endl;
+ }
+ );
+
+ lifecycleService->SetAbortHandler(
+ [](auto /*participantState*/) {
+ std::cout << "Simulation is aborting" << std::endl;
+ }
+ );
+
+
+If a participant does not use the virtual time synchronization, a separate callback informs about the transition to the ``Running`` state.
+This can be used to start local timers::
+
+ lifecycleService->SetStartingHandler(
+ []() {
+ std::cout << "Starting" << std::endl;
+ }
+ );
+
+The |CommunicationReadyHandler| should be used to initialize and configure :doc:`services and controllers`.
+
+Communication guarantees
+""""""""""""""""""""""""
+
+The following communication guarantees apply to participants that utilize a Lifecycle Service and are limited to RPC and Publish/Subscribe services.
+Bus systems have definitions on the protocol level for message acknowledgement.
+For RPC or Publish/Subscribe however, communication guarantees depend on the implementation.
+In the SIL Kit, the |CommunicationReadyHandler| handler is the first point at which guarantees can be given.
+This implies that |StartLifecycle| has already been called.
+Remote services that have been created at the point a participant calls |StartLifecycle| will be available for communication as soon as the |CommunicationReadyHandler| is triggered.
+As an example, a call to |Publish| on a |IDataPublisher| on participant A in the |CommunicationReadyHandler| is guaranteed to arrive at
+participant B if its |IDataSubscriber| has been created before participant A has called |StartLifecycle|.
+
+Communication in the |CommunicationReadyHandler| between participants that use the |OperationMode_Coordinated| is guaranteed.
+After |StartLifecycle| is called, these participants will wait for each other until all reached the |ServicesCreatedState| state.
+Therefore all services have already been created when the |CommunicationReadyHandler| is triggered.
+
+A common use-case where the guarantee also applies is described as follows: A participant with |OperationMode_Autonomous| wants to join an already running simulation.
+In this case, the services of the running participants have been created and the newly joining participant can communicate in the |CommunicationReadyHandler|.
+
+If several participants are defined with |OperationMode_Autonomous| and are executed 'simultaneously' in a distributed setup, their intention is to proceed through the lifecycle states without coordination.
+In this case, there is no deterministic execution order of controller creation and calls to |StartLifecycle| across the processes.
+Therefore, it is impossible to guarantee that a remote subscriber already exists at the time a participants tries to |Publish| in the |CommunicationReadyHandler|.
+Without the useage of a lifecycle, there is no way to synchronize controller creation across different participants.
+In other words, controllers can appear at any time and there is no call to the SIL Kit API to build up a communication guarantee on.
+In cases were such guarantees are indespensable, it is recommended to use a |ILifecycleService|.
+
+Note that a |IDataPublisher| can be defined with a history (of length 1).
+This guarantees the delivery of the last publication but is not coupled to the lifecycle states.
+
+Another guarantee can be given for communication in the SimulationStepHandler.
+All participants that take part in the distributed time algorithm are ready to exchange messages if the first SimulationStepHandler is triggered, regardless of their |OperationMode|.
+
+
+Controlling the Participant
+"""""""""""""""""""""""""""
+
+
+After a successful startup, the participant will enter the |RunningState| state.
+|State| returns the current state as a plain enumeration, whereas |Status| returns additional information such as the participant's name, the human-readable reason for entering the state, and the wall clock time when the state was entered.
+
+
+To temporarily pause a simulation task, the |Pause| method can be invoked with a human-readable explanation as a string argument.
+Execution can be resumed using the |Continue| method.
+
+
+To abort the simulation and report an error message, use the |ReportError| method.
+This will change the current participant state to the |ErrorState| state and report the error message to the SIL Kit runtime system.
+|ReportError| is also called when the invocation of a registered handler throws an exception.
+
+To stop a particular participant, use the |Stop| method.
+This will exit |RunningState| or |PausedState|, call the registered ``StopHandler`` (if it was set) and switch to the |StoppedState| state.
+Afterwards, the participant will shut down by first changing to the |ShuttingDownState| state, which triggers the shutdown handler (if it was set) and then finishing at the |ShutdownState| state.
+At this point, the future provided by |StartLifecycle| will return.
+
+API Reference
+-------------
+
+.. doxygenclass:: SilKit::Services::Orchestration::ILifecycleService
+ :members:
+
+Handlers
+""""""""
+
+.. doxygentypedef:: SilKit::Services::Orchestration::CommunicationReadyHandler
+.. doxygentypedef:: SilKit::Services::Orchestration::StartingHandler
+.. doxygentypedef:: SilKit::Services::Orchestration::StopHandler
+.. doxygentypedef:: SilKit::Services::Orchestration::ShutdownHandler
+.. doxygentypedef:: SilKit::Services::Orchestration::AbortHandler
+
+Data Structures
+"""""""""""""""
+
+.. doxygenstruct:: SilKit::Services::Orchestration::LifecycleConfiguration
+.. doxygenenum:: SilKit::Services::Orchestration::OperationMode
+
+.. doxygenstruct:: SilKit::Services::Orchestration::WorkflowConfiguration
+.. doxygenstruct:: SilKit::Services::Orchestration::ParticipantConnectionInformation
+
+Usage Example
+--------------
+
+The following example is based on the ``SilKitCanDemo`` source code which is distributed with the SIL Kit, and slightly adapted for clarity.
+It demonstrates how to setup a lifecycle service and register callbacks to monitor participant state changes.
+
+To demonstrate how to properly initialize other services, a CAN controller is initialized within the ``CommunicationReady`` callback of the lifecycle service.
+This is the recommended way to set up controllers before first use.
+
+.. literalinclude::
+ examples/sync/LifecycleNoSyncSample.cpp
+ :language: cpp
diff --git a/docs/api/lin.rst b/docs/api/lin.rst
index 595794c2d..e21ef26cc 100644
--- a/docs/api/lin.rst
+++ b/docs/api/lin.rst
@@ -1,428 +1,428 @@
-.. _sec:lin:
-
-===================
-LIN Service API
-===================
-
-.. Macros for docs use
-.. |IParticipant| replace:: :cpp:class:`IParticipant`
-.. |CreateLinController| replace:: :cpp:func:`CreateLinController`
-.. |ILinController| replace:: :cpp:class:`ILinController`
-
-.. |Init| replace:: :cpp:func:`Init()`
-.. |SendFrame| replace:: :cpp:func:`SendFrame()`
-.. |SendFrameHeader| replace:: :cpp:func:`SendFrameHeader()`
-.. |UpdateTxBuffer| replace:: :cpp:func:`UpdateTxBuffer()`
-.. |SetFrameResponse| replace:: :cpp:func:`SetFrameResponse()`
-
-.. |Wakeup| replace:: :cpp:func:`Wakeup()`
-.. |GoToSleep| replace:: :cpp:func:`GoToSleep()`
-
-.. |AddFrameStatusHandler| replace:: :cpp:func:`AddFrameStatusHandler()`
-.. |AddGoToSleepHandler| replace:: :cpp:func:`AddGoToSleepHandler()`
-.. |AddWakeupHandler| replace:: :cpp:func:`AddWakeupHandler()`
-
-.. |RemoveFrameStatusHandler| replace:: :cpp:func:`RemoveFrameStatusHandler()`
-.. |RemoveGoToSleepHandler| replace:: :cpp:func:`RemoveGoToSleepHandler()`
-.. |RemoveWakeupHandler| replace:: :cpp:func:`RemoveWakeupHandler()`
-
-.. |FrameStatusHandler| replace:: :cpp:type:`FrameStatusHandler`
-.. |GoToSleepHandler| replace:: :cpp:type:`GoToSleepHandler`
-.. |WakeupHandler| replace:: :cpp:type:`WakeupHandler`
-.. |LinSlaveConfigurationHandler| replace:: :cpp:type:`LinSlaveConfigurationHandler`
-
-.. |LinFrameStatusEvent| replace:: :cpp:class:`LinFrameStatusEvent`
-.. |LinGoToSleepEvent| replace:: :cpp:class:`LinGoToSleepEvent`
-.. |LinWakeupEvent| replace:: :cpp:class:`LinWakeupEvent`
-.. |LinSlaveConfigurationEvent| replace:: :cpp:class:`LinSlaveConfigurationEvent`
-
-.. |LinControllerConfig| replace:: :cpp:class:`LinControllerConfig`
-.. |LinFrameResponse| replace:: :cpp:class:`LinFrameResponse`
-.. |LinFrame| replace:: :cpp:class:`LinFrame`
-
-.. |LinControllerMode| replace:: :cpp:enum:`LinControllerMode`
-.. |LinControllerMode_Master| replace:: :cpp:enumerator:`LinControllerMode::Master`
-.. |LinControllerMode_Slave| replace:: :cpp:enumerator:`LinControllerMode::Slave`
-
-.. |LinFrameResponseType_MasterResponse| replace:: :cpp:enumerator:`LinFrameResponseType::MasterResponse`
-.. |LinFrameResponseType_SlaveResponse| replace:: :cpp:enumerator:`LinFrameResponseType::SlaveResponse`
-.. |LinFrameResponseType_SlaveToSlave| replace:: :cpp:enumerator:`LinFrameResponseType::SlaveToSlave`
-
-.. |LinFrameResponseMode_Rx| replace:: :cpp:enumerator:`LinFrameResponseMode::Rx`
-.. |LinFrameResponseMode_Tx| replace:: :cpp:enumerator:`LinFrameResponseMode::TxUnconditional`
-
-.. |LinChecksumModel| replace:: :cpp:enum:`LinFrameStatus::LinChecksumModel`
-.. |LinChecksumModel_Undefined| replace:: :cpp:enumerator:`LinFrameStatus::LinChecksumModel::Unknown`
-
-.. |LinDataLength| replace:: :cpp:type:`LinDataLength`
-.. |LinDataLengthUnknown| replace:: :cpp:var:`LinDataLengthUnknown`
-
-.. |LinFrameStatus| replace:: :cpp:enum:`LinFrameStatus`
-.. |LinFrameStatus_LIN_RX_OK| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_OK`
-.. |LinFrameStatus_LIN_TX_OK| replace:: :cpp:enumerator:`LinFrameStatus::LIN_TX_OK`
-.. |LinFrameStatus_LIN_TX_ERROR| replace:: :cpp:enumerator:`LinFrameStatus::LIN_TX_ERROR`
-.. |LinFrameStatus_LIN_RX_ERROR| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_ERROR`
-.. |LinFrameStatus_LIN_RX_NO_RESPONSE| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_NO_RESPONSE`
-
-.. |HandlerId| replace:: :cpp:class:`HandlerId`
-
-.. contents::
- :local:
- :depth: 3
-
-
-.. highlight:: cpp
-
-Using the LIN Controller
--------------------------
-
-The LIN Service API provides a LIN bus abstraction through the |ILinController| interface.
-A LIN controller is created by calling |CreateLinController| given a controller and network name::
-
- auto* linMasterController = participant->CreateLinController("LinMaster", "LIN1");
-
-LIN controllers will only communicate within the same network.
-
-.. _sec:lin-initialization:
-
-Initialization
-~~~~~~~~~~~~~~
-
-Before the LIN Controller can be used, it must be initialized. The initialization is performed by setting up a
-|LinControllerConfig| and passing it to |Init|. The |LinControllerMode| must be set to either
-|LinControllerMode_Master| or |LinControllerMode_Slave| and the baud rate must be specified. Further, the
-|LinControllerConfig| provides the configuration on which LIN IDs the controller will receive
-(|LinFrameResponseMode_Rx|) or respond to (|LinFrameResponseMode_Tx|) frames.
-
-The following example configures a LIN controller as a LIN slave with a baud rate of 20'000 baud. Furthermore, LIN ID
-0x11 is configured for transmission::
-
- LinFrameResponse response;
- response.frame.id = 0x11;
- response.frame.checksumModel = LinChecksumModel::Enhanced;
- response.frame.dataLength = 8;
- response.frame.data = {1, 2, 3, 4, 5, 6, 7, 8};
- response.responseMode = LinFrameResponseMode::TxUnconditional;
-
- LinControllerConfig slaveConfig;
- slaveConfig.controllerMode = LinControllerMode::Slave;
- slaveConfig.baudRate = 20000;
- slaveConfig.frameResponses.push_back(response);
-
- linController->Init(slaveConfig);
-
-Note that |Init| must only be called once. A second call of |Init| or operations on an uninitialized LIN node will
-result in an exception. For the configuration, also keep in mind that the LIN protocol allows multiple nodes to be
-configured for reception, but only one node to provide a response. This restriction is not evaluated upon |Init|,
-but only during operation.
-
-Extending the configuration during operation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Initialized LIN nodes can use |SetFrameResponse| to configure a response or reception during operation.
-|SetFrameResponse| is useful for cases where a LIN slave is not aware of its full configuration upon initialization.
-Reconfiguration of already used ID on the particular node are discarded. If used on a slave, the new configuration
-will become active once the master receives the updated configuration.
-
-For a LIN master, the AUTOSAR API |SendFrame| will also extend the configuration and can be used for IDs not explicitly
-defined in |Init|. If used with |LinFrameResponseType_MasterResponse|, the master will configure
-|LinFrameResponseMode_Tx|, if used with |LinFrameResponseType_SlaveResponse|, the master will configure
-|LinFrameResponseMode_Rx| on the given ID. In case of |LinFrameResponseType_SlaveToSlave|, no reconfiguration takes place,
-but the master will receive a call to its |FrameStatusHandler| with |LinFrameStatus_LIN_TX_OK|, confirming the
-initiation of the slave-to-slave communication.
-
-Initiating LIN Transmissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Data is transferred in the form of a |LinFrame|, reception and acknowledgement is handled in the |FrameStatusHandler|.
-A LIN master can initiate the transmission of a frame using the AUTOSAR API |SendFrame| or the non-AUTOSAR API
-|SendFrameHeader|. If a LIN slave provides the response, |SendFrame| requires that a corresponding frame
-response was configured before at a LIN slave using |Init| or |SetFrameResponse|.
-
-If using |SendFrame| with |LinFrameResponseType_MasterResponse|, the response doesn't have to be preconfigured and the
-payload provided in the frame parameter of |SendFrame| will be used. If the LIN master uses the non-AUTOSAR API
-|SendFrameHeader|, a LIN node has to be configured with |LinFrameResponseMode_Tx| on that ID, possibly the master
-itself.
-
-In all cases except |SendFrame| with |LinFrameResponseType_MasterResponse|, the responding node will receive the
-header and complete the transmission using the payload of its current transmit buffer. The buffer can be updated
-with |UpdateTxBuffer| on the node that is configured with |LinFrameResponseMode_Tx| for the corresponding ID.
-
-Sending Data
-____________
-
-The transmission of a frame can be initiated using |SendFrame| or |SendFrameHeader|:
-
-1. Using |SendFrame| with |LinFrameResponseType_MasterResponse|, the frame can be sent in one call
- and the master provides both header and response. A |LinFrame| must be setup with the LIN ID,
- data, data length and the desired checksum model::
-
- // Prepare a frame with id 0x10 for transmission
- LinFrame masterFrame;
- masterFrame.id = 0x10;
- masterFrame.dataLength = 8;
- masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};
- masterFrame.checksumModel = LinChecksumModel::Enhanced;
-
- // initiate the frame transmission using the AUTOSAR interface
- master->SendFrame(masterFrame, LinFrameResponseType::MasterResponse);
-
-2. When using |SendFrame| with |LinFrameResponseType_SlaveResponse| or |LinFrameResponseType_SlaveToSlave|,
- a slave has to be preconfigured with |LinFrameResponseMode_Tx| on that ID. With these response types, only the
- ID of the |LinFrame| used in |SendFrame| is taken into account. The actual payload and frame settings are provided
- by the Tx buffer of the responing slave. The following example assumes that a slave is configured as seen in
- :ref:`Initialization`::
-
- // The slave is configured to respond on ID 0x11
- LinFrame slaveResponseFrame;
- slaveResponseFrame.id = 0x11;
-
- // initiate the frame transmission using the AUTOSAR interface
- master->SendFrame(slaveResponseFrame, LinFrameResponseType::SlaveResponse);
-
-Using |SendFrame| with |LinFrameResponseType_SlaveResponse| assumes that the master is interested in the response
-and will configure itself for reception (|LinFrameResponseMode_Rx|).
-
-3. When using |SendFrameHeader|, the transmission is initiated by sending the header. The node (either master or slave) configured with
- |LinFrameResponseMode_Tx| will provide the response. The actual payload and frame settings are
- provided by the Tx buffer of the responing LIN node. The following example also assumes that a slave is
- configured as seen in :ref:`Initialization`::
-
- // Slave:
- LinFrame updatedSlaveResponse;
- updatedSlaveResponse.id = 0x11;
- updatedSlaveResponse.dataLength = 8;
- updatedSlaveResponse.data = {'S', 'L', 'A', 'V', 'E', 1, 2, 3};
- updatedSlaveResponse.checksumModel = LinChecksumModel::Enhanced;
- slave->UpdateTxBuffer(updatedSlaveResponse);
-
- // Master:
- // Transmit the frame header, the response will be provided by the slave.
- master->SendFrameHeader(0x11);
-
-Transmission acknowledgement
-____________________________
-
-To be notified for the success or failure of the transmission, a |FrameStatusHandler| should be registered using
-|AddFrameStatusHandler|::
-
- // Register FrameStatusHandler to receive data from the LIN slave
- auto frameStatusHandler =
- [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
- master->AddFrameStatusHandler(frameStatusHandler);
-
-A successful transmission is confirmed via the registered callback, for example::
-
- frameStatusHandler(master, frameStatusEvent);
- // With:
- // frameStatusEvent.timestamp: timeEndOfFrame;
- // frameStatusEvent.frame: masterFrame;
- // frameStatusEvent.status: LinFrameStatus::LIN_TX_OK;
-
-If multiple controllers have configured |LinFrameResponseMode_Tx| on the same LIN ID, a collision occurs on the bus,
-which is indicated by |LinFrameStatus_LIN_TX_ERROR|.
-
-Receiving data from a slave
-___________________________
-
-Beside transmission acknowledgements, the |FrameStatusHandler| is also used for reception. To receive data, the
-|FrameStatusHandler| must be registered using |AddFrameStatusHandler|, which is called by the LIN controller when
-a frame is received and the LIN node is configured for reception with |LinFrameResponseMode_Rx| on that LIN ID::
-
- // Register FrameStatusHandler to receive data from the LIN slave
- auto frameStatusHandler =
- [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
- master->AddFrameStatusHandler(frameStatusHandler);
-
-The incoming |LinFrameStatusEvent| holds a |LinFrameStatus| indicating the success (|LinFrameStatus_LIN_RX_OK|) or
-failure (|LinFrameStatus_LIN_RX_ERROR|) of the transmission. If a LIN slave has previously setup a matching
-|LinFrameResponse| for transmission, the registered |FrameStatusHandler| will deliver a |LinFrameStatusEvent| as
-follows::
-
- frameStatusHandler(master, frameStatusEvent);
- // With:
- // frameStatusEvent.timestamp: timeEndOfFrame;
- // frameStatusEvent.frame: slaveFrame;
- // frameStatusEvent.status: LinFrameStatus::LIN_RX_OK;
-
-If more than one slave provided a response, the master will receive a |LinFrameStatus_LIN_RX_ERROR|, the slaves will
-see |LinFrameStatus_LIN_TX_ERROR|.
-
-Data length and checksum model
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A |LinDataLength| and |LinChecksumModel| can be provided for a given ID when configuring a reception or initiating a
-transmission. A frame will arrive with |LinFrameStatus_LIN_RX_ERROR| if there is a mismatch between configured and
-received data length or checksum model. However, a LIN node configured for reception might not know beforehand about the
-data length or checksum model provided in the response. In this case, the reception can be configured with the
-wildcards |LinDataLengthUnknown| or |LinChecksumModel_Undefined| in the respective paramters of the |LinFrame| and the
-data length or checksum model provided by the sender is used in the |FrameStatusHandler|.
-
-Managing the event handlers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Adding a handler will return a |HandlerId| which can be used to remove the handler via:
-
-- |RemoveFrameStatusHandler|
-- |RemoveGoToSleepHandler|
-- |RemoveWakeupHandler|
-
-
-API and Data Type Reference
----------------------------
-
-LIN Controller API
-~~~~~~~~~~~~~~~~~~~~
-
-.. doxygenclass:: SilKit::Services::Lin::ILinController
- :members:
-
-Data Structures
-~~~~~~~~~~~~~~~
-
-.. doxygenstruct:: SilKit::Services::Lin::LinFrame
- :members:
-.. doxygenstruct:: SilKit::Services::Lin::LinFrameResponse
- :members:
-.. doxygenstruct:: SilKit::Services::Lin::LinControllerConfig
- :members:
-.. doxygenstruct:: SilKit::Services::Lin::LinFrameStatusEvent
- :members:
-.. doxygenstruct:: SilKit::Services::Lin::LinWakeupEvent
- :members:
-.. doxygenstruct:: SilKit::Services::Lin::LinGoToSleepEvent
- :members:
-
-Enumerations and Typedefs
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. doxygentypedef:: SilKit::Services::Lin::LinId
-.. doxygenenum:: SilKit::Services::Lin::LinChecksumModel
-.. doxygentypedef:: SilKit::Services::Lin::LinDataLength
-.. doxygenvariable:: SilKit::Services::Lin::LinDataLengthUnknown
-.. doxygenenum:: SilKit::Services::Lin::LinFrameResponseType
-.. doxygenenum:: SilKit::Services::Lin::LinFrameResponseMode
-.. doxygenenum:: SilKit::Services::Lin::LinFrameStatus
-.. doxygenenum:: SilKit::Services::Lin::LinControllerMode
-.. doxygentypedef:: SilKit::Services::Lin::LinBaudRate
-.. doxygenenum:: SilKit::Services::Lin::LinControllerStatus
-
-Usage Examples
---------------
-
-This section contains more complex examples that show the interaction of two or more LIN controllers. Although the LIN
-controllers would typically belong to different participants and reside in different processes, their interaction is
-shown here sequentially to demonstrate cause and effect.
-
-Assumptions:
-
-- Variables ``master``, ``slave``, ``slave1``, and ``slave2`` are of type |ILinController|.
-- Variable ``timeEndOfFrame`` indicates the end of frame time stamp when using the detailed simulation. Otherwise, the value of
- ``timeEndOfFrame`` is undefined.
-- ``UseAutosarInterface`` is a boolean variable that indicates whether to use the AUTOSAR API or the non-AUTOSAR API.
- It will most likely not be used in practice, and only serves to show the various uses of the API.
-
-Successful Transmission from Master to slave
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows a successful data transfer from a LIN master to a LIN slave. The transmission must be initiated by
-the master.
-
-.. literalinclude::
- examples/lin/Master_to_Slave_LIN_TX_OK.cpp
- :language: cpp
-
-Successful Transmission from slave to Master
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows a successful data transfer from a LIN slave to a LIN master. The transmission must be initiated by
-the master.
-
-.. literalinclude::
- examples/lin/Slave_to_Master_LIN_RX_OK.cpp
- :language: cpp
-
-Successful Transmission from slave to slave
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows how data is transferred from one LIN slave to another one. The data transfer must be initiated by a
-LIN master.
-
-.. literalinclude::
- examples/lin/Slave_to_Slave_LIN_TX_OK.cpp
- :language: cpp
-
-Erroneous Transmission from Master to Slave - Multiple Responses
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows what happens when a master attempts to send a Frame while there is slave that has configured a Tx
-response for the same LIN ID.
-
-.. literalinclude::
- examples/lin/Master_to_Slave_LIN_TX_ERROR.cpp
- :language: cpp
-
-Erroneous Transmission from Slave to Master - No Response
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows what happens when a master initiates a transmission and no slave has configured a Tx response for
-this LIN ID.
-
-.. literalinclude::
- examples/lin/Slave_to_Master_LIN_RX_NO_RESPONSE.cpp
- :language: cpp
-
-
-Erroneous Transmission from Slave to Master - Multiple Responses
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows what happens when a master initiates a transmission where multiple slaves have configured Tx
-responses for the same LIN ID.
-
-.. literalinclude::
- examples/lin/Slave_to_Master_LIN_RX_ERROR.cpp
- :language: cpp
-
-Go To Sleep
-~~~~~~~~~~~
-
-This example shows how to use |GoToSleep| and when the controller will switch from operational to sleep mode.
-
-.. literalinclude::
- examples/lin/Go_To_Sleep.cpp
- :language: cpp
-
-.. admonition:: Note
-
- The |GoToSleepHandler| is triggered even without configuring ID ``0x3C`` for reception. However, the
- |FrameStatusHandler| for slaves is only called if ID ``0x3C`` is configured for reception. The master initiated
- the sleep mode, it's |FrameStatusHandler| is called with |LinFrameStatus_LIN_TX_OK|.
-
-Wake Up
-~~~~~~~
-
-This example shows how to |Wakeup| a LIN bus. The example assumes that both master and slave are currently in sleep mode.
-I.e., the situation corresponds to the end of the previous example.
-
-.. literalinclude::
- examples/lin/Wake_Up.cpp
- :language: cpp
-
-Aggregated view of responding LIN slaves (experimental)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This example shows how the |LinSlaveConfigurationHandler| provides direct access to the |LinFrameResponse| configuration of
-all slaves. This can be used by a LIN master to predict if a slave response will be provided prior to the use of |SendFrame|
-or |SendFrameHeader|. It is primarily intended for diagnostic purposes and not required for regular operation of a LIN
-controller. The calls `AddLinSlaveConfigurationHandler`, `RemoveLinSlaveConfigurationHandler` and `GetSlaveConfiguration`
-reside in the `SilKit::Experimental::Services::Lin` namespace and might be changed or removed in future versions.
-
-.. literalinclude::
- examples/lin/LinSlaveConfigurationHandler.cpp
- :language: cpp
-
-The experimental API is defined as follows:
-
-.. doxygenfunction:: SilKit::Experimental::Services::Lin::AddLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController* linController, SilKit::Experimental::Services::Lin::LinSlaveConfigurationHandler handler)
-.. doxygenfunction:: SilKit::Experimental::Services::Lin::RemoveLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController* linController, SilKit::Util::HandlerId handlerId)
-.. doxygenfunction:: SilKit::Experimental::Services::Lin::GetSlaveConfiguration(SilKit::Services::Lin::ILinController* linController)
+.. _chap:lin-service-api:
+
+===================
+LIN Service API
+===================
+
+.. Macros for docs use
+.. |IParticipant| replace:: :cpp:class:`IParticipant`
+.. |CreateLinController| replace:: :cpp:func:`CreateLinController`
+.. |ILinController| replace:: :cpp:class:`ILinController`
+
+.. |Init| replace:: :cpp:func:`Init()`
+.. |SendFrame| replace:: :cpp:func:`SendFrame()`
+.. |SendFrameHeader| replace:: :cpp:func:`SendFrameHeader()`
+.. |UpdateTxBuffer| replace:: :cpp:func:`UpdateTxBuffer()`
+.. |SetFrameResponse| replace:: :cpp:func:`SetFrameResponse()`
+
+.. |Wakeup| replace:: :cpp:func:`Wakeup()`
+.. |GoToSleep| replace:: :cpp:func:`GoToSleep()`
+
+.. |AddFrameStatusHandler| replace:: :cpp:func:`AddFrameStatusHandler()`
+.. |AddGoToSleepHandler| replace:: :cpp:func:`AddGoToSleepHandler()`
+.. |AddWakeupHandler| replace:: :cpp:func:`AddWakeupHandler()`
+
+.. |RemoveFrameStatusHandler| replace:: :cpp:func:`RemoveFrameStatusHandler()`
+.. |RemoveGoToSleepHandler| replace:: :cpp:func:`RemoveGoToSleepHandler()`
+.. |RemoveWakeupHandler| replace:: :cpp:func:`RemoveWakeupHandler()`
+
+.. |FrameStatusHandler| replace:: :cpp:type:`FrameStatusHandler`
+.. |GoToSleepHandler| replace:: :cpp:type:`GoToSleepHandler`
+.. |WakeupHandler| replace:: :cpp:type:`WakeupHandler`
+.. |LinSlaveConfigurationHandler| replace:: :cpp:type:`LinSlaveConfigurationHandler`
+
+.. |LinFrameStatusEvent| replace:: :cpp:class:`LinFrameStatusEvent`
+.. |LinGoToSleepEvent| replace:: :cpp:class:`LinGoToSleepEvent`
+.. |LinWakeupEvent| replace:: :cpp:class:`LinWakeupEvent`
+.. |LinSlaveConfigurationEvent| replace:: :cpp:class:`LinSlaveConfigurationEvent`
+
+.. |LinControllerConfig| replace:: :cpp:class:`LinControllerConfig`
+.. |LinFrameResponse| replace:: :cpp:class:`LinFrameResponse`
+.. |LinFrame| replace:: :cpp:class:`LinFrame`
+
+.. |LinControllerMode| replace:: :cpp:enum:`LinControllerMode`
+.. |LinControllerMode_Master| replace:: :cpp:enumerator:`LinControllerMode::Master`
+.. |LinControllerMode_Slave| replace:: :cpp:enumerator:`LinControllerMode::Slave`
+
+.. |LinFrameResponseType_MasterResponse| replace:: :cpp:enumerator:`LinFrameResponseType::MasterResponse`
+.. |LinFrameResponseType_SlaveResponse| replace:: :cpp:enumerator:`LinFrameResponseType::SlaveResponse`
+.. |LinFrameResponseType_SlaveToSlave| replace:: :cpp:enumerator:`LinFrameResponseType::SlaveToSlave`
+
+.. |LinFrameResponseMode_Rx| replace:: :cpp:enumerator:`LinFrameResponseMode::Rx`
+.. |LinFrameResponseMode_Tx| replace:: :cpp:enumerator:`LinFrameResponseMode::TxUnconditional`
+
+.. |LinChecksumModel| replace:: :cpp:enum:`LinFrameStatus::LinChecksumModel`
+.. |LinChecksumModel_Undefined| replace:: :cpp:enumerator:`LinFrameStatus::LinChecksumModel::Unknown`
+
+.. |LinDataLength| replace:: :cpp:type:`LinDataLength`
+.. |LinDataLengthUnknown| replace:: :cpp:var:`LinDataLengthUnknown`
+
+.. |LinFrameStatus| replace:: :cpp:enum:`LinFrameStatus`
+.. |LinFrameStatus_LIN_RX_OK| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_OK`
+.. |LinFrameStatus_LIN_TX_OK| replace:: :cpp:enumerator:`LinFrameStatus::LIN_TX_OK`
+.. |LinFrameStatus_LIN_TX_ERROR| replace:: :cpp:enumerator:`LinFrameStatus::LIN_TX_ERROR`
+.. |LinFrameStatus_LIN_RX_ERROR| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_ERROR`
+.. |LinFrameStatus_LIN_RX_NO_RESPONSE| replace:: :cpp:enumerator:`LinFrameStatus::LIN_RX_NO_RESPONSE`
+
+.. |HandlerId| replace:: :cpp:class:`HandlerId`
+
+.. contents::
+ :local:
+ :depth: 3
+
+
+.. highlight:: cpp
+
+Using the LIN Controller
+-------------------------
+
+The LIN Service API provides a LIN bus abstraction through the |ILinController| interface.
+A LIN controller is created by calling |CreateLinController| given a controller and network name::
+
+ auto* linMasterController = participant->CreateLinController("LinMaster", "LIN1");
+
+LIN controllers will only communicate within the same network.
+
+.. _sec:lin-initialization:
+
+Initialization
+~~~~~~~~~~~~~~
+
+Before the LIN Controller can be used, it must be initialized. The initialization is performed by setting up a
+|LinControllerConfig| and passing it to |Init|. The |LinControllerMode| must be set to either
+|LinControllerMode_Master| or |LinControllerMode_Slave| and the baud rate must be specified. Further, the
+|LinControllerConfig| provides the configuration on which LIN IDs the controller will receive
+(|LinFrameResponseMode_Rx|) or respond to (|LinFrameResponseMode_Tx|) frames.
+
+The following example configures a LIN controller as a LIN slave with a baud rate of 20'000 baud. Furthermore, LIN ID
+0x11 is configured for transmission::
+
+ LinFrameResponse response;
+ response.frame.id = 0x11;
+ response.frame.checksumModel = LinChecksumModel::Enhanced;
+ response.frame.dataLength = 8;
+ response.frame.data = {1, 2, 3, 4, 5, 6, 7, 8};
+ response.responseMode = LinFrameResponseMode::TxUnconditional;
+
+ LinControllerConfig slaveConfig;
+ slaveConfig.controllerMode = LinControllerMode::Slave;
+ slaveConfig.baudRate = 20000;
+ slaveConfig.frameResponses.push_back(response);
+
+ linController->Init(slaveConfig);
+
+Note that |Init| must only be called once. A second call of |Init| or operations on an uninitialized LIN node will
+result in an exception. For the configuration, also keep in mind that the LIN protocol allows multiple nodes to be
+configured for reception, but only one node to provide a response. This restriction is not evaluated upon |Init|,
+but only during operation.
+
+Extending the configuration during operation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Initialized LIN nodes can use |SetFrameResponse| to configure a response or reception during operation.
+|SetFrameResponse| is useful for cases where a LIN slave is not aware of its full configuration upon initialization.
+Reconfiguration of already used ID on the particular node are discarded. If used on a slave, the new configuration
+will become active once the master receives the updated configuration.
+
+For a LIN master, the AUTOSAR API |SendFrame| will also extend the configuration and can be used for IDs not explicitly
+defined in |Init|. If used with |LinFrameResponseType_MasterResponse|, the master will configure
+|LinFrameResponseMode_Tx|, if used with |LinFrameResponseType_SlaveResponse|, the master will configure
+|LinFrameResponseMode_Rx| on the given ID. In case of |LinFrameResponseType_SlaveToSlave|, no reconfiguration takes place,
+but the master will receive a call to its |FrameStatusHandler| with |LinFrameStatus_LIN_TX_OK|, confirming the
+initiation of the slave-to-slave communication.
+
+Initiating LIN Transmissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data is transferred in the form of a |LinFrame|, reception and acknowledgement is handled in the |FrameStatusHandler|.
+A LIN master can initiate the transmission of a frame using the AUTOSAR API |SendFrame| or the non-AUTOSAR API
+|SendFrameHeader|. If a LIN slave provides the response, |SendFrame| requires that a corresponding frame
+response was configured before at a LIN slave using |Init| or |SetFrameResponse|.
+
+If using |SendFrame| with |LinFrameResponseType_MasterResponse|, the response doesn't have to be preconfigured and the
+payload provided in the frame parameter of |SendFrame| will be used. If the LIN master uses the non-AUTOSAR API
+|SendFrameHeader|, a LIN node has to be configured with |LinFrameResponseMode_Tx| on that ID, possibly the master
+itself.
+
+In all cases except |SendFrame| with |LinFrameResponseType_MasterResponse|, the responding node will receive the
+header and complete the transmission using the payload of its current transmit buffer. The buffer can be updated
+with |UpdateTxBuffer| on the node that is configured with |LinFrameResponseMode_Tx| for the corresponding ID.
+
+Sending Data
+____________
+
+The transmission of a frame can be initiated using |SendFrame| or |SendFrameHeader|:
+
+1. Using |SendFrame| with |LinFrameResponseType_MasterResponse|, the frame can be sent in one call
+ and the master provides both header and response. A |LinFrame| must be setup with the LIN ID,
+ data, data length and the desired checksum model::
+
+ // Prepare a frame with id 0x10 for transmission
+ LinFrame masterFrame;
+ masterFrame.id = 0x10;
+ masterFrame.dataLength = 8;
+ masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};
+ masterFrame.checksumModel = LinChecksumModel::Enhanced;
+
+ // initiate the frame transmission using the AUTOSAR interface
+ master->SendFrame(masterFrame, LinFrameResponseType::MasterResponse);
+
+2. When using |SendFrame| with |LinFrameResponseType_SlaveResponse| or |LinFrameResponseType_SlaveToSlave|,
+ a slave has to be preconfigured with |LinFrameResponseMode_Tx| on that ID. With these response types, only the
+ ID of the |LinFrame| used in |SendFrame| is taken into account. The actual payload and frame settings are provided
+ by the Tx buffer of the responing slave. The following example assumes that a slave is configured as seen in
+ :ref:`Initialization`::
+
+ // The slave is configured to respond on ID 0x11
+ LinFrame slaveResponseFrame;
+ slaveResponseFrame.id = 0x11;
+
+ // initiate the frame transmission using the AUTOSAR interface
+ master->SendFrame(slaveResponseFrame, LinFrameResponseType::SlaveResponse);
+
+Using |SendFrame| with |LinFrameResponseType_SlaveResponse| assumes that the master is interested in the response
+and will configure itself for reception (|LinFrameResponseMode_Rx|).
+
+3. When using |SendFrameHeader|, the transmission is initiated by sending the header. The node (either master or slave) configured with
+ |LinFrameResponseMode_Tx| will provide the response. The actual payload and frame settings are
+ provided by the Tx buffer of the responing LIN node. The following example also assumes that a slave is
+ configured as seen in :ref:`Initialization`::
+
+ // Slave:
+ LinFrame updatedSlaveResponse;
+ updatedSlaveResponse.id = 0x11;
+ updatedSlaveResponse.dataLength = 8;
+ updatedSlaveResponse.data = {'S', 'L', 'A', 'V', 'E', 1, 2, 3};
+ updatedSlaveResponse.checksumModel = LinChecksumModel::Enhanced;
+ slave->UpdateTxBuffer(updatedSlaveResponse);
+
+ // Master:
+ // Transmit the frame header, the response will be provided by the slave.
+ master->SendFrameHeader(0x11);
+
+Transmission acknowledgement
+____________________________
+
+To be notified for the success or failure of the transmission, a |FrameStatusHandler| should be registered using
+|AddFrameStatusHandler|::
+
+ // Register FrameStatusHandler to receive data from the LIN slave
+ auto frameStatusHandler =
+ [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
+ master->AddFrameStatusHandler(frameStatusHandler);
+
+A successful transmission is confirmed via the registered callback, for example::
+
+ frameStatusHandler(master, frameStatusEvent);
+ // With:
+ // frameStatusEvent.timestamp: timeEndOfFrame;
+ // frameStatusEvent.frame: masterFrame;
+ // frameStatusEvent.status: LinFrameStatus::LIN_TX_OK;
+
+If multiple controllers have configured |LinFrameResponseMode_Tx| on the same LIN ID, a collision occurs on the bus,
+which is indicated by |LinFrameStatus_LIN_TX_ERROR|.
+
+Receiving data from a slave
+___________________________
+
+Beside transmission acknowledgements, the |FrameStatusHandler| is also used for reception. To receive data, the
+|FrameStatusHandler| must be registered using |AddFrameStatusHandler|, which is called by the LIN controller when
+a frame is received and the LIN node is configured for reception with |LinFrameResponseMode_Rx| on that LIN ID::
+
+ // Register FrameStatusHandler to receive data from the LIN slave
+ auto frameStatusHandler =
+ [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
+ master->AddFrameStatusHandler(frameStatusHandler);
+
+The incoming |LinFrameStatusEvent| holds a |LinFrameStatus| indicating the success (|LinFrameStatus_LIN_RX_OK|) or
+failure (|LinFrameStatus_LIN_RX_ERROR|) of the transmission. If a LIN slave has previously setup a matching
+|LinFrameResponse| for transmission, the registered |FrameStatusHandler| will deliver a |LinFrameStatusEvent| as
+follows::
+
+ frameStatusHandler(master, frameStatusEvent);
+ // With:
+ // frameStatusEvent.timestamp: timeEndOfFrame;
+ // frameStatusEvent.frame: slaveFrame;
+ // frameStatusEvent.status: LinFrameStatus::LIN_RX_OK;
+
+If more than one slave provided a response, the master will receive a |LinFrameStatus_LIN_RX_ERROR|, the slaves will
+see |LinFrameStatus_LIN_TX_ERROR|.
+
+Data length and checksum model
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A |LinDataLength| and |LinChecksumModel| can be provided for a given ID when configuring a reception or initiating a
+transmission. A frame will arrive with |LinFrameStatus_LIN_RX_ERROR| if there is a mismatch between configured and
+received data length or checksum model. However, a LIN node configured for reception might not know beforehand about the
+data length or checksum model provided in the response. In this case, the reception can be configured with the
+wildcards |LinDataLengthUnknown| or |LinChecksumModel_Undefined| in the respective paramters of the |LinFrame| and the
+data length or checksum model provided by the sender is used in the |FrameStatusHandler|.
+
+Managing the event handlers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Adding a handler will return a |HandlerId| which can be used to remove the handler via:
+
+- |RemoveFrameStatusHandler|
+- |RemoveGoToSleepHandler|
+- |RemoveWakeupHandler|
+
+
+API and Data Type Reference
+---------------------------
+
+LIN Controller API
+~~~~~~~~~~~~~~~~~~~~
+
+.. doxygenclass:: SilKit::Services::Lin::ILinController
+ :members:
+
+Data Structures
+~~~~~~~~~~~~~~~
+
+.. doxygenstruct:: SilKit::Services::Lin::LinFrame
+ :members:
+.. doxygenstruct:: SilKit::Services::Lin::LinFrameResponse
+ :members:
+.. doxygenstruct:: SilKit::Services::Lin::LinControllerConfig
+ :members:
+.. doxygenstruct:: SilKit::Services::Lin::LinFrameStatusEvent
+ :members:
+.. doxygenstruct:: SilKit::Services::Lin::LinWakeupEvent
+ :members:
+.. doxygenstruct:: SilKit::Services::Lin::LinGoToSleepEvent
+ :members:
+
+Enumerations and Typedefs
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. doxygentypedef:: SilKit::Services::Lin::LinId
+.. doxygenenum:: SilKit::Services::Lin::LinChecksumModel
+.. doxygentypedef:: SilKit::Services::Lin::LinDataLength
+.. doxygenvariable:: SilKit::Services::Lin::LinDataLengthUnknown
+.. doxygenenum:: SilKit::Services::Lin::LinFrameResponseType
+.. doxygenenum:: SilKit::Services::Lin::LinFrameResponseMode
+.. doxygenenum:: SilKit::Services::Lin::LinFrameStatus
+.. doxygenenum:: SilKit::Services::Lin::LinControllerMode
+.. doxygentypedef:: SilKit::Services::Lin::LinBaudRate
+.. doxygenenum:: SilKit::Services::Lin::LinControllerStatus
+
+Usage Examples
+--------------
+
+This section contains more complex examples that show the interaction of two or more LIN controllers. Although the LIN
+controllers would typically belong to different participants and reside in different processes, their interaction is
+shown here sequentially to demonstrate cause and effect.
+
+Assumptions:
+
+- Variables ``master``, ``slave``, ``slave1``, and ``slave2`` are of type |ILinController|.
+- Variable ``timeEndOfFrame`` indicates the end of frame time stamp when using the detailed simulation. Otherwise, the value of
+ ``timeEndOfFrame`` is undefined.
+- ``UseAutosarInterface`` is a boolean variable that indicates whether to use the AUTOSAR API or the non-AUTOSAR API.
+ It will most likely not be used in practice, and only serves to show the various uses of the API.
+
+Successful Transmission from Master to slave
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows a successful data transfer from a LIN master to a LIN slave. The transmission must be initiated by
+the master.
+
+.. literalinclude::
+ examples/lin/Master_to_Slave_LIN_TX_OK.cpp
+ :language: cpp
+
+Successful Transmission from slave to Master
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows a successful data transfer from a LIN slave to a LIN master. The transmission must be initiated by
+the master.
+
+.. literalinclude::
+ examples/lin/Slave_to_Master_LIN_RX_OK.cpp
+ :language: cpp
+
+Successful Transmission from slave to slave
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows how data is transferred from one LIN slave to another one. The data transfer must be initiated by a
+LIN master.
+
+.. literalinclude::
+ examples/lin/Slave_to_Slave_LIN_TX_OK.cpp
+ :language: cpp
+
+Erroneous Transmission from Master to Slave - Multiple Responses
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows what happens when a master attempts to send a Frame while there is slave that has configured a Tx
+response for the same LIN ID.
+
+.. literalinclude::
+ examples/lin/Master_to_Slave_LIN_TX_ERROR.cpp
+ :language: cpp
+
+Erroneous Transmission from Slave to Master - No Response
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows what happens when a master initiates a transmission and no slave has configured a Tx response for
+this LIN ID.
+
+.. literalinclude::
+ examples/lin/Slave_to_Master_LIN_RX_NO_RESPONSE.cpp
+ :language: cpp
+
+
+Erroneous Transmission from Slave to Master - Multiple Responses
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows what happens when a master initiates a transmission where multiple slaves have configured Tx
+responses for the same LIN ID.
+
+.. literalinclude::
+ examples/lin/Slave_to_Master_LIN_RX_ERROR.cpp
+ :language: cpp
+
+Go To Sleep
+~~~~~~~~~~~
+
+This example shows how to use |GoToSleep| and when the controller will switch from operational to sleep mode.
+
+.. literalinclude::
+ examples/lin/Go_To_Sleep.cpp
+ :language: cpp
+
+.. admonition:: Note
+
+ The |GoToSleepHandler| is triggered even without configuring ID ``0x3C`` for reception. However, the
+ |FrameStatusHandler| for slaves is only called if ID ``0x3C`` is configured for reception. The master initiated
+ the sleep mode, it's |FrameStatusHandler| is called with |LinFrameStatus_LIN_TX_OK|.
+
+Wake Up
+~~~~~~~
+
+This example shows how to |Wakeup| a LIN bus. The example assumes that both master and slave are currently in sleep mode.
+I.e., the situation corresponds to the end of the previous example.
+
+.. literalinclude::
+ examples/lin/Wake_Up.cpp
+ :language: cpp
+
+Aggregated view of responding LIN slaves (experimental)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example shows how the |LinSlaveConfigurationHandler| provides direct access to the |LinFrameResponse| configuration of
+all slaves. This can be used by a LIN master to predict if a slave response will be provided prior to the use of |SendFrame|
+or |SendFrameHeader|. It is primarily intended for diagnostic purposes and not required for regular operation of a LIN
+controller. The calls `AddLinSlaveConfigurationHandler`, `RemoveLinSlaveConfigurationHandler` and `GetSlaveConfiguration`
+reside in the `SilKit::Experimental::Services::Lin` namespace and might be changed or removed in future versions.
+
+.. literalinclude::
+ examples/lin/LinSlaveConfigurationHandler.cpp
+ :language: cpp
+
+The experimental API is defined as follows:
+
+.. doxygenfunction:: SilKit::Experimental::Services::Lin::AddLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController* linController, SilKit::Experimental::Services::Lin::LinSlaveConfigurationHandler handler)
+.. doxygenfunction:: SilKit::Experimental::Services::Lin::RemoveLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController* linController, SilKit::Util::HandlerId handlerId)
+.. doxygenfunction:: SilKit::Experimental::Services::Lin::GetSlaveConfiguration(SilKit::Services::Lin::ILinController* linController)
diff --git a/docs/api/logging.rst b/docs/api/logging.rst
index 1e9dd9662..72eb91589 100644
--- a/docs/api/logging.rst
+++ b/docs/api/logging.rst
@@ -1,3 +1,5 @@
+.. _chap:logging-service-api:
+
===================
Logging Service API
===================
diff --git a/docs/api/pubsub.rst b/docs/api/pubsub.rst
index 374d75388..228ceff9b 100644
--- a/docs/api/pubsub.rst
+++ b/docs/api/pubsub.rst
@@ -16,6 +16,7 @@
.. |MediaTypeData| replace:: :cpp:func:`MediaTypeData()`
+.. _chap:pubsub-service-api:
==========================
Data Publish/Subscribe API
diff --git a/docs/api/rpc.rst b/docs/api/rpc.rst
index c2d66c616..dc01d4f5f 100644
--- a/docs/api/rpc.rst
+++ b/docs/api/rpc.rst
@@ -25,6 +25,9 @@
.. |MediaTypeRpc| replace:: :cpp:func:`MediaTypeRpc()`
+.. |CoordinatedLifecycle| replace:: :ref:`coordinated lifecycle`
+
+.. _chap:rpc-service-api:
===============================
RPC (Remote Procedure Call) API
@@ -54,7 +57,7 @@ The |IRpcClient| is instantiated from an |IParticipant| instance by calling the
}
SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.resultData)};
- std::cout << "sum is " << deserializer.Deserialize() << " with user context " << event.userContext << std::endl;
+ std::cout << "sum is " << deserializer.Deserialize(32) << " with user context " << event.userContext << std::endl;
};
SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
@@ -73,8 +76,8 @@ The callback provides the user context pointer passed to |Call| or |CallWithTime
SilKit::Util::SerDes::Serializer serializer;
serializer.BeginStruct();
- serializer.Serialize(uint32_t{31});
- serializer.Serialize(uint32_t{11});
+ serializer.Serialize(uint32_t{31}, 32);
+ serializer.Serialize(uint32_t{11}, 32);
serializer.EndStruct();
client->Call(serializer.ReleaseBuffer());
@@ -95,18 +98,18 @@ The |IRpcServer| must submit the answer to the call at a later point in time wit
auto rpcCallHandler = [](IRpcServer* server, const RpcCallEvent& event) {
SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.argumentData)};
deserializer.BeginStruct();
- const auto lhs = deserializer.Deserialize();
- const auto rhs = deserializer.Deserialize();
+ const auto lhs = deserializer.Deserialize(32);
+ const auto rhs = deserializer.Deserialize(32);
deserializer.EndStruct();
SilKit::Util::SerDes::Serializer serializer;
- serializer.Serialize(lhs + rhs);
+ serializer.Serialize(lhs + rhs, 32);
server->SubmitResult(event.callHandle, serializer.ReleaseBuffer());
};
SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
- auto* server = participant->CreateRpcServer("AddServer, rpcSpec, rpcCallHandler);
+ auto* server = participant->CreateRpcServer("AddServer", rpcSpec, rpcCallHandler);
Argument and return data is represented as a byte vector, so the serialization schema can be chosen by the user.
Nonetheless, it is highly recommended to use SIL Kit's :doc:`Data Serialization/Deserialization API` to ensure compatibility among all SIL Kit participants.
@@ -118,6 +121,11 @@ Usage Examples
Example: Simple Calculator
--------------------------
+In this example, the RPC Server offers a simple function for adding two numbers.
+The example shows the usage of the RPC Server / Client and data (de-)serialization.
+Note that the availability of the RPC Server is not guaranteed and will depend on the starting order of the two participants.
+The next example shows how a coordinated lifecycle can be set up to guarantee the reception of the RPC client call.
+
Server - Addition
~~~~~~~~~~~~~~~~~
@@ -126,18 +134,18 @@ Server - Addition
auto rpcCallHandler = [](IRpcServer* server, const RpcCallEvent& event) {
SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.argumentData)};
deserializer.BeginStruct();
- const auto lhs = deserializer.Deserialize();
- const auto rhs = deserializer.Deserialize();
+ const auto lhs = deserializer.Deserialize(32);
+ const auto rhs = deserializer.Deserialize(32);
deserializer.EndStruct();
SilKit::Util::SerDes::Serializer serializer;
- serializer.Serialize(lhs + rhs);
+ serializer.Serialize(lhs + rhs, 32);
server->SubmitResult(event.callHandle, serializer.ReleaseBuffer());
};
SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
- auto* server = participant->CreateRpcServer("AddServer, rpcSpec, rpcCallHandler);
+ auto* server = participant->CreateRpcServer("AddServer", rpcSpec, rpcCallHandler);
Client - Addition
~~~~~~~~~~~~~~~~~
@@ -151,20 +159,125 @@ Client - Addition
}
SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.resultData)};
- std::cout << "sum is " << deserializer.Deserialize() << std::endl;
+ std::cout << "sum is " << deserializer.Deserialize(32) << std::endl;
};
SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
auto* client = participant->CreateRpcClient("AddClient", rpcSpec, rpcCallResultHandler);
+ std::this_thread::sleep_for(1s);
+
SilKit::Util::SerDes::Serializer serializer;
serializer.BeginStruct();
- serializer.Serialize(uint32_t{31});
- serializer.Serialize(uint32_t{11});
+ serializer.Serialize(uint32_t{31}, 32);
+ serializer.Serialize(uint32_t{11}, 32);
serializer.EndStruct();
client->Call(serializer.ReleaseBuffer());
+
+Example: RPC with guaranteed call reception
+-------------------------------------------
+
+This example is based on the previous one and includes participant creation and the setup of a |CoordinatedLifecycle|.
+This guarantees that the RPC client and server are validly connected at the time the client makes the call.
+
+Server - Addition
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: cpp
+
+ #include
+
+ #include "silkit/SilKit.hpp"
+ #include "silkit/services/rpc/all.hpp"
+ #include "silkit/services/orchestration/all.hpp"
+ #include "silkit/util/serdes/Serialization.hpp"
+
+ using namespace SilKit::Services::Orchestration;
+ using namespace SilKit::Services::Rpc;
+
+ int main(int argc, char** argv)
+ {
+ auto config = SilKit::Config::ParticipantConfigurationFromString("");
+ auto participant = SilKit::CreateParticipant(config, "Server", "silkit://localhost:8500");
+ auto* lifecycleService = participant->CreateLifecycleService({OperationMode::Coordinated});
+
+ auto rpcCallHandler = [](IRpcServer* server, const RpcCallEvent& event) {
+ SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.argumentData)};
+ deserializer.BeginStruct();
+ const auto lhs = deserializer.Deserialize(32);
+ const auto rhs = deserializer.Deserialize(32);
+ deserializer.EndStruct();
+
+ SilKit::Util::SerDes::Serializer serializer;
+ serializer.Serialize(lhs + rhs, 32);
+
+ std::cout << "Server function 'Add' is called with parameters: " << lhs << ", " << rhs << std::endl;
+ server->SubmitResult(event.callHandle, serializer.ReleaseBuffer());
+ };
+
+ SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
+ auto* server = participant->CreateRpcServer("AddServer", rpcSpec, rpcCallHandler);
+
+ auto finalStateFuture = lifecycleService->StartLifecycle();
+ finalStateFuture.get();
+
+ return 0;
+ }
+
+Client - Addition
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: cpp
+
+ #include
+
+ #include "silkit/SilKit.hpp"
+ #include "silkit/services/rpc/all.hpp"
+ #include "silkit/services/orchestration/all.hpp"
+ #include "silkit/util/serdes/Serialization.hpp"
+
+ using namespace SilKit::Services::Orchestration;
+ using namespace SilKit::Services::Rpc;
+
+ int main(int argc, char** argv)
+ {
+ auto config = SilKit::Config::ParticipantConfigurationFromString("");
+ auto participant = SilKit::CreateParticipant(config, "Client", "silkit://localhost:8500");
+ auto* lifecycleService = participant->CreateLifecycleService({OperationMode::Coordinated});
+
+ auto rpcCallResultHandler = [](IRpcClient*, const RpcCallResultEvent& event) {
+ if (event.callStatus != SilKit::Services::Rpc::RpcCallStatus::Success)
+ {
+ return;
+ }
+
+ SilKit::Util::SerDes::Deserializer deserializer{SilKit::Util::ToStdVector(event.resultData)};
+ std::cout << "Client obtained result: " << deserializer.Deserialize(32) << std::endl;
+ };
+
+ SilKit::Services::Rpc::RpcSpec rpcSpec{"Add", SilKit::Util::SerDes::MediaTypeRpc()};
+ auto* client = participant->CreateRpcClient("AddClient", rpcSpec, rpcCallResultHandler);
+
+ lifecycleService->SetCommunicationReadyHandler([client]() {
+ SilKit::Util::SerDes::Serializer serializer;
+ serializer.BeginStruct();
+ serializer.Serialize(uint32_t{31}, 32);
+ serializer.Serialize(uint32_t{11}, 32);
+ serializer.EndStruct();
+
+ std::cout << "Client calls: 'Add(31, 11)'" << std::endl;
+ client->Call(serializer.ReleaseBuffer());
+ });
+
+ auto finalStateFuture = lifecycleService->StartLifecycle();
+ finalStateFuture.get();
+
+ return 0;
+ }
+
+
API and Data Type Reference
===========================
diff --git a/docs/api/timeSyncService.rst b/docs/api/timeSyncService.rst
index 23908b98d..8189b7f32 100644
--- a/docs/api/timeSyncService.rst
+++ b/docs/api/timeSyncService.rst
@@ -1,4 +1,4 @@
-.. _sec:api-timesync-service:
+.. _chap:timesync-service-api:
============================
Time Synchronization Service
diff --git a/docs/overview/overview.inc b/docs/overview/overview.inc
index 2a0e57056..54cc2b1d3 100644
--- a/docs/overview/overview.inc
+++ b/docs/overview/overview.inc
@@ -6,21 +6,26 @@ Vector SIL Kit Overview
.. |NetSim| replace:: Network Simulator
.. |_| unicode:: 0xA0
:trim:
-
+.. |CAN-API| replace:: :ref:`CAN / CAN FD`
+.. |Ethernet-API| replace:: :ref:`Ethernet`
+.. |Flexray-API| replace:: :ref:`FlexRay`
+.. |LIN-API| replace:: :ref:`LIN`
+.. |Lifecycle-API| replace:: :ref:`lifecycle`
+.. |Timesync-API| replace:: :ref:`time synchronization`
+.. |Logging-API| replace:: :ref:`logging`
The Vector |ProductName| is an open source library for connecting Software-in-the-Loop Environments.
+It provides:
-Vector |ProductName| provides
-
-* communication infrastructure for automotive and non-automotive applications
+* Communication infrastructure for automotive and non-automotive applications
-* interoperability between any SIL Kit enabled applications
+* Interoperability between any SIL Kit enabled applications
-* cross platform communication
+* Cross platform communication
- * implemented in C++ w/o platform dependencies
+* Implemented in C++ w/o platform dependencies
- * interoperability between Windows, Linux, and other UNIX derivates​
+* Interoperability between Windows, Linux, and other UNIX derivates​
* Stable API and ABI as well as long-term network layer compatibility
@@ -29,13 +34,13 @@ Vector |ProductName| provides
Supported Services
------------------
-The currently supported services of the |ProductName| consist of the following categories:
+The services currently supported by the |ProductName| consist of the following categories:
-* **Vehicle Network Controllers:** CAN / CAN |_| FD, Ethernet, FlexRay, and LIN
-* **Data Publish/Subscribe:** exchange of arbitrary data
-* **RPC Servers/Clients:** for dynamic remote procedure execution
-* **Orchestration:** for lifecycle and time synchronization control
-* **Logging:** for logging messages into a file, standard output, or to other participants
+* **Vehicle Network Controllers:** |CAN-API|, |Ethernet-API|, |Flexray-API|, and |LIN-API|
+* **Data Publish/Subscribe:** topic-based :ref:`publish/subscribe` mechanism to exchange arbitrary data
+* **RPC Servers/Clients:** for dynamic :ref:`remote procedure execution`
+* **Orchestration:** for |Lifecycle-API| and |Timesync-API| control
+* **Logging:** for |Logging-API| messages into a file, standard output, or to other participants
Vehicle Networks
----------------
diff --git a/docs/simulation/simulation.rst b/docs/simulation/simulation.rst
index d806dff88..e1a59d2d4 100644
--- a/docs/simulation/simulation.rst
+++ b/docs/simulation/simulation.rst
@@ -30,6 +30,11 @@ Simulation
.. |SetParticipantConnectedHandler| replace:: :cpp:func:`SetParticipantConnectedHandler()`
.. |SetParticipantDisconnectedHandler| replace:: :cpp:func:`SetParticipantDisconnectedHandler()`
+.. |DataPublisher| replace:: :cpp:class:`DataPublisher`
+.. |DataSubscriber| replace:: :cpp:class:`DataSubscriber`
+.. |RpcClient| replace:: :cpp:class:`RpcClient`
+.. |RpcServer| replace:: :cpp:class:`RpcServer`
+
..
Section references
.. |LifecycleService| replace:: :ref:`Lifecycle Service`
@@ -159,6 +164,8 @@ Each participant has an independent lifecycle that other participants can observ
: |ProductName| participant state machine.
+.. _subsubsec:sim-lifecycle-starting-a-simulation:
+
Starting a Simulation
~~~~~~~~~~~~~~~~~~~~~
@@ -168,7 +175,7 @@ This will cause the |LifecycleService| to announce its state as :cpp:enumerator:
A participant that uses the lifecycle service may choose to coordinate its state with other participants by creating the |ILifecycleService| with |OperationMode_Coordinated|.
In that case, they will align their participant state based on the current system state until they reach :cpp:enumerator:`CommunicationInitialized`.
-Once the system state also changes to CommunicationInitialized, the communication between all participants via :cpp:class:`DataPublisher` and :cpp:class:`DataSubscriber` is possible.
+Once the system state also changes to CommunicationInitialized, the communication between all participants via PubSub / RPC is possible.
This information is propagated to the user if they registered the callback via :cpp:func:`SetCommunicationReadyHandler()`.
Once the callback is finished, the participant state changes to :cpp:enumerator:`ReadyToRun`.
The participant will wait for the system state to change to :cpp:enumerator:`ReadyToRun` as well and then proceeds to the :cpp:enumerator:`Running` state.