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.