LIN Service API

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.

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::TxUnconditional) 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::TxUnconditional, 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 acknowledgment 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::TxUnconditional 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::TxUnconditional 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::TxUnconditional 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 responding slave. The following example assumes that a slave is configured as seen in 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).

  1. When using SendFrameHeader(), the transmission is initiated by sending the header. The node (either master or slave) configured with LinFrameResponseMode::TxUnconditional will provide the response. The actual payload and frame settings are provided by the TX buffer of the responding LIN node. The following example also assumes that a slave is configured as seen in 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 acknowledgment

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::TxUnconditional 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 acknowledgment, 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 LinFrameStatus::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 (255) or LinFrameStatus::LinChecksumModel::Unknown in the respective parameters of the LinFrame. If the wildcards are used, the validation of the incoming data length or checksum model are skipped. The values provided by the sender are then used in the FrameStatusHandler.

Managing the event handlers

Adding a handler will return a HandlerId which can be used to remove the handler via:

API and Data Type Reference

LIN Controller API

class ILinController

The LIN controller can assume the role of a LIN master or a LIN slave. All LIN nodes must be configured with their respective role using ILinController::Init(LinControllerConfig) to perform data transmission and reception.

AUTOSAR-like LIN interface:

non-AUTOSAR LIN interface:

Public Types

using CallbackT = std::function<void(ILinController *controller, const MsgT &msg)>

Generic LIN callback method.

using FrameStatusHandler = CallbackT<LinFrameStatusEvent>

Callback type to indicate the end of a LIN LinFrame transmission. Cf., AddFrameStatusHandler(FrameStatusHandler);

using GoToSleepHandler = CallbackT<LinGoToSleepEvent>

Callback type to indicate that a go-to-sleep frame has been received. Cf., AddGoToSleepHandler(GoToSleepHandler);

using WakeupHandler = CallbackT<LinWakeupEvent>

Callback type to indicate that a wakeup pulse has been received. Cf., AddWakeupHandler(WakeupHandler);

Public Functions

virtual ~ILinController() = default
virtual void Init(LinControllerConfig config) = 0

Initialize the LIN controller defining its role and RX/TX configuration.

All controllers must be initialized exactly once to take part in LIN communication.

AUTOSAR Name: Lin_Init

Parameters

config – The controller configuration contains:

Throws
  • SilKit::StateError – if the LIN Controller is configured with LinControllerMode::Inactive

  • SilKit::StateError – if Init() is called a second time on this LIN Controller.

  • SilKit::StateError – if InitDynamic() has already been called on the LIN Controller.

virtual auto Status() const noexcept -> LinControllerStatus = 0

Get the current status of the LIN Controller, i.e., Operational or Sleep.

virtual void SendFrame(LinFrame frame, LinFrameResponseType responseType) = 0

Initiate a LIN data transfer of a given LinFrameResponseType (AUTOSAR LIN master interface)

The responseType determines if frame.data is used for the frame response or if a different node has to provide it:

  • MasterResponse: SilKit::Services::Lin::LinFrame is sent from this controller to all connected slaves using frame.data. The LIN Master doesn’t have to be configured with LinFrameResponseMode::TxUnconditional on this LIN ID.

  • SlaveResponse: the frame response must be provided by a connected slave and is received by this controller.

  • SlaveToSlave: the frame response must be provided by a connected slave and is ignored by this controller.

AUTOSAR Name: Lin_SendFrame

Parameters
  • frame – Provides the LIN identifier, checksum model, and optional data.

  • responseType – Determines which LIN Node will provide the frame response.

Throws
  • SilKit::StateError – if the LIN Controller is not initialized or not a master node.

  • SilKit::StateError – if InitDynamic() has been called on the LIN Controller.

virtual void SendFrameHeader(LinId linId) = 0

Initiate a LIN data transfer by sending a LIN header (AUTOSAR LIN master interface)

Parameters

linId – Provides the LIN header identifier. The node that is configured to respond on this ID will complete the transmission and provide the response data.

Throws

SilKit::StateError – if the LIN Controller is not initialized or not a master node.

virtual void UpdateTxBuffer(LinFrame frame) = 0

Update the response data. The LIN controller needs to be configured with TxUnconditional on this ID.

Parameters

frame – Provides the LIN ID and data used for the update.

Throws
  • SilKit::StateError – if the LIN Controller is not initialized.

  • SilKit::ConfigurationError – if the LIN Controller is not configured with TxUnconditional on this ID.

  • SilKit::StateError – if InitDynamic() has been called on the LIN Controller.

virtual void SetFrameResponse(LinFrameResponse response) = 0

Set a RX/TX configuration during operation.

Parameters

response – The frame and response mode to be configured.

Throws
  • SilKit::StateError – if the LIN Controller is not initialized.

  • SilKit::StateError – if InitDynamic() has been called on the LIN Controller.

virtual void GoToSleep() = 0

Transmit a go-to-sleep-command and set ControllerState::Sleep and enable wake-up.

AUTOSAR Name: Lin_GoToSleep

Throws

SilKit::StateError – if the LIN Controller is not initialized or not a master node.

virtual void GoToSleepInternal() = 0

Set ControllerState::Sleep without sending a go-to-sleep command.

AUTOSAR Name: Lin_GoToSleepInternal

Throws

SilKit::StateError – if the LIN Controller is not initialized.

virtual void Wakeup() = 0

Generate a wake up pulse and set ControllerState::Operational.

AUTOSAR Name: Lin_Wakeup

Throws

SilKit::StateError – if the LIN Controller is not initialized.

virtual void WakeupInternal() = 0

Set ControllerState::Operational without generating a wake up pulse.

AUTOSAR Name: Lin_WakeupInternal

Throws

SilKit::StateError – if the LIN Controller is not initialized.

virtual auto AddFrameStatusHandler(FrameStatusHandler handler) -> HandlerId = 0

Reports the SilKit::Services::Lin::LinFrameStatus of a LIN SilKit::Services::Lin::LinFrame transmission and provides the transmitted frame.

The FrameStatusHandler is used for reception and acknowledgement of LIN frames. The direction (prefixed with LIN_TX_ or LIN_RX_) and error state of the tranmission is encoded in the SilKit::Services::Lin::LinFrameStatus.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

virtual void RemoveFrameStatusHandler(HandlerId handlerId) = 0

Remove a FrameStatusHandler by SilKit::Util::HandlerId on this controller.

Parameters

handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

virtual auto AddGoToSleepHandler(GoToSleepHandler handler) -> HandlerId = 0

The GoToSleepHandler is called whenever a go-to-sleep frame is received.

Note: The LIN controller does not automatically enter sleep mode on reception of a go-to-sleep frame. I.e., GoToSleepInternal() must be called manually.

Note: This handler will always be called, independently of the SilKit::Services::Lin::LinFrameResponseMode configuration for LIN ID 0x3C. However, regarding the FrameStatusHandler, the go-to-sleep frame is treated like every other frame, i.e. the FrameStatusHandler is only called for LIN ID 0x3C if configured as LinFrameResponseMode::Rx.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

virtual void RemoveGoToSleepHandler(HandlerId handlerId) = 0

Remove a GoToSleepHandler by SilKit::Util::HandlerId on this controller.

Parameters

handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

virtual auto AddWakeupHandler(WakeupHandler handler) -> HandlerId = 0

The WakeupHandler is called whenever a wake up pulse is received.

Note: The LIN controller does not automatically enter operational mode on wake up pulse detection. I.e., WakeInternal() must be called manually.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

virtual void RemoveWakeupHandler(HandlerId handlerId) = 0

Remove a WakeupHandler by SilKit::Util::HandlerId on this controller.

Parameters

handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

Data Structures

struct LinFrame

A LIN LinFrame.

This Type is used to provide LIN ID, checksum model, data length and data.

AUTOSAR Name: Lin_PduType

Public Members

LinId id = {0}

Lin Identifier.

LinChecksumModel checksumModel = {LinChecksumModel::Unknown}

Checksum Model.

LinDataLength dataLength = {0}

Data length.

std::array<uint8_t, 8> data = {}

The actual payload.

struct LinFrameResponse

Configuration data for a LIN Slave task for a particular LIN ID.

Public Members

LinFrame frame

frame must provide the LIN LinId for which the response is configured.

If responseMode is LinFrameResponseMode::TxUnconditional, the frame data is used for the transaction.

LinFrameResponseMode responseMode = {LinFrameResponseMode::Unused}

Determines if the LinFrameResponse is used for transmission (TxUnconditional), reception (Rx) or ignored (Unused).

struct LinControllerConfig

Configuration data to initialize the LIN Controller Cf.: ILinController::Init(LinControllerConfig config);

Public Members

LinControllerMode controllerMode = {LinControllerMode::Inactive}

Configure as LIN master or LIN slave.

LinBaudRate baudRate = {0}

The operational baud rate of the controller. Used in a detailed simulation.

std::vector<LinFrameResponse> frameResponses

Optional LinFrameResponse configuration.

FrameResponses can also be configured at a later point using ILinController::UpdateTxBuffer() and ILinController::SetFrameResponses().

struct LinFrameStatusEvent

A LIN frame status event delivered in the ILinController::FrameStatusHandler.

Public Members

std::chrono::nanoseconds timestamp

Time of the event.

LinFrame frame
LinFrameStatus status
struct LinWakeupEvent

A LIN wakeup event delivered in the ILinController::WakeupHandler.

Public Members

std::chrono::nanoseconds timestamp

Time of the event.

TransmitDirection direction

The direction of the wakeup pulse.

struct LinGoToSleepEvent

A LIN wakeup event delivered in the ILinController::GoToSleepHandler.

Public Members

std::chrono::nanoseconds timestamp

Time of the event.

Enumerations and Typedefs

using SilKit::Services::Lin::LinId = SilKit_LinId

The identifier of a LIN LinFrame.

This type represents all valid identifier used by ILinController::SendFrame(), ILinController::SendFrameHeader().

Range: 0…0x3F

enum SilKit::Services::Lin::LinChecksumModel

The checksum model of a LIN SilKit::Services::Lin::LinFrame.

This type is used to specify the Checksum model to be used for the LIN LinFrame.

AUTOSAR Name: Lin_FrameCsModelType

Values:

enumerator Unknown

Unknown checksum model. If configured with this value, the checksum model of the first reception will be used.

enumerator Enhanced

Enhanced checksum model.

enumerator Classic

Classic checksum model.

using SilKit::Services::Lin::LinDataLength = SilKit_LinDataLength

The data length of a LIN LinFrame in bytes.

This type is used to specify the number of data bytes to copy.

AUTOSAR Name: Lin_FrameDlType

Range: 0…8

const LinDataLength SilKit::Services::Lin::LinDataLengthUnknown = SilKit_LinDataLengthUnknown

If configured for reception with this value, the data length validation of incoming frames is skipped.

enum SilKit::Services::Lin::LinFrameResponseType

Controls the behavior of ILinController::SendFrame()

Determines whether the master also provides a frame response or if the frame response is expected to be provided from a slave.

AUTOSAR Name: Lin_FrameResponseType

Values:

enumerator MasterResponse

Response is generated from this master node.

enumerator SlaveResponse

Response is generated from a remote slave node.

enumerator SlaveToSlave

Response is generated from one slave to and received by another slave, for the master the response will be anonymous, it does not have to receive the response.

enum SilKit::Services::Lin::LinFrameResponseMode

Controls the behavior of a LIN Slave task for a particular LIN ID.

Values:

enumerator Unused

The LinFrameResponse corresponding to the ID is neither received nor transmitted by the LIN slave.

enumerator Rx

The LinFrameResponse corresponding to the ID is received by the LIN slave.

enumerator TxUnconditional

The LinFrameResponse corresponding to the ID is transmitted unconditionally by the LIN slave.

enum SilKit::Services::Lin::LinFrameStatus

The state of a LIN transmission.

Used to indicate the success or failure of a LIN transmission to a registered ILinController::FrameStatusHandler.

Note: the enumeration values directly correspond to the AUTOSAR type Lin_StatusType. Not all values are used in the SIL Kit.

AUTOSAR Doc: LIN operation states for a LIN channel or frame, as returned by the API service Lin_GetStatus().

Values:

enumerator NOT_OK

(currently not in use)

AUROSAR Doc: Development or production error occurred

enumerator LIN_TX_OK

The controller successfully transmitted a frame response.

AUTOSAR Doc: Successful transmission.

enumerator LIN_TX_BUSY

(currently not in use)

AUTOSAR Doc: Ongoing transmission (Header or Response).

enumerator LIN_TX_HEADER_ERROR

(currently not in use)

AUTOSAR Doc: Erroneous header transmission such as: Mismatch between sent and read back data, Identifier parity error, or Physical bus error

enumerator LIN_TX_ERROR

(currently not in use)

AUTOSAR Doc: Erroneous response transmission such as: Mismatch between sent and read back data, Physical bus error

enumerator LIN_RX_OK

The controller received a correct frame response.

AUTOSAR Doc: Reception of correct response.

enumerator LIN_RX_BUSY

(currently not in use)

AUTOSAR Doc: Ongoing reception: at least one response byte has been received, but the checksum byte has not been received.

enumerator LIN_RX_ERROR

The reception of a response failed.

Indicates a mismatch in expected and received data length or a checksum error. Checksum errors occur when multiple slaves are configured to transmit the same frame or when the sender and receiver use different checksum models.

AUTOSAR Doc: Erroneous response reception such as: Framing error, Overrun error, Checksum error, or Short response

enumerator LIN_RX_NO_RESPONSE

No LIN controller did provide a response to the frame header.

AUTOSAR Doc: No response byte has been received so far.

enum SilKit::Services::Lin::LinControllerMode

Used to configure a LIN controller as a master or slave.

Cf. LinControllerConfig, ILinController::Init()

Values:

enumerator Inactive

The LIN controller has not been configured yet and is inactive. This does not indicate sleep mode.

enumerator Master

A LIN controller with active master task and slave task.

enumerator Slave

A LIN controller with only a slave task.

using SilKit::Services::Lin::LinBaudRate = SilKit_LinBaudRate

The operational baud rate of the controller.

Range: 200…20’000 Bd

enum SilKit::Services::Lin::LinControllerStatus

The operational state of the controller, i.e., operational or sleeping.

Values:

enumerator Unknown

The controller state is not yet known.

enumerator Operational

Normal operation.

enumerator Sleep

Sleep state operation; in this state wake-up detection from slave nodes.

enumerator SleepPending

Sleep pending state is reached when a GoToSleep is issued.

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Slave Setup
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup LinFrameResponseMode::Rx for LIN ID 0x10 and 0x11 on the slave
LinFrame slaveFrame;
slaveFrame.id = 0x10;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 0, 0, 0};
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::Rx});

slaveFrame.id = 0x11;
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::Rx});

slave->Init(slaveConfig);

// Register FrameStatusHandler to receive data
auto slave_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
slave->AddFrameStatusHandler(slave_FrameStatusHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

// Setup LinFrameResponseMode::TxUnconditional for LIN ID 0x11 on the master
LinFrame masterFrame;
masterFrame.id = 0x11;
masterFrame.dataLength = 8;
masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};
masterFrame.checksumModel = LinChecksumModel::Enhanced;
masterConfig.frameResponses.push_back(LinFrameResponse{masterFrame, LinFrameResponseMode::TxUnconditional});

master->Init(masterConfig);

// Register FrameStatusHandler to receive confirmation of the successful transmission
auto master_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

if (UseAutosarInterface)
{ 
    // Transmit the frame 0x10 without configuration on master, slave has configured RX for 0x10.
    LinFrame masterFrame;
    masterFrame.id = 0x10;
    masterFrame.checksumModel = LinChecksumModel::Enhanced;
    masterFrame.dataLength = 8;
    masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};

    // AUTOSAR API
    master->SendFrame(masterFrame, LinFrameResponseType::MasterResponse);
}
else
{
    // Alternative, non-AUTOSAR API
    // Transmit the frame header, the master response is configured.
    master->SendFrameHeader(0x11);
}

// In both cases (AUTOSAR and non-AUTOSAR), the following callbacks will be triggered:
//  - TX confirmation for the master, who initiated the transmission
//    and provided the frame response
master_FrameStatusHandler(master, LinFrameStatusEvent{ timeEndOfFrame, masterFrame, LinFrameStatus::LIN_TX_OK });
//  - RX for the slave, who received the frame response
slave_FrameStatusHandler(slave, LinFrameStatusEvent{ timeEndOfFrame, masterFrame, LinFrameStatus::LIN_RX_OK });

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Slave Setup
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup LinFrameResponseMode::TxUnconditional for LIN ID 0x10 and 0x11 on the slave
LinFrame slaveFrame;
slaveFrame.id = 0x10;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 1, 0, 0};
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slaveFrame.id = 0x11;
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slave->Init(slaveConfig);

// Register FrameStatusHandler to receive an acknowledgement for
// the successful transmission
auto slave_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
slave->AddFrameStatusHandler(slave_FrameStatusHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

// Setup LinFrameResponseMode::Rx for LIN ID 0x11 on the master
LinFrame masterFrame;
masterFrame.id = 0x11;
masterFrame.dataLength = 8;
masterFrame.checksumModel = LinChecksumModel::Enhanced;

masterConfig.frameResponses.push_back(LinFrameResponse{masterFrame, LinFrameResponseMode::Rx});

master->Init(masterConfig);

// Register FrameStatusHandler to receive data from the LIN slave
auto master_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

// ------------------------------------------------------------
// Perform TX from slave to master, i.e., the slave provides the
// frame response, the master receives it.
if (UseAutosarInterface)
{
    // AUTOSAR API
    LinFrame frameRequest;
    frameRequest.id = 0x10;
    frameRequest.checksumModel = LinChecksumModel::Enhanced;

    master->SendFrame(frameRequest, LinFrameResponseType::SlaveResponse);
}
else
{
    // Alternative, non-AUTOSAR API
    master->SendFrameHeader(0x11);
}

// In both cases (AUTOSAR and non-AUTOSAR), the following callbacks will be triggered:
//  - RX for the master, who received the frame response
master_FrameStatusHandler(master, LinFrameStatusEvent{ timeEndOfFrame, slaveFrame, LinFrameStatus::LIN_RX_OK });
//  - TX confirmation for the slave, who provided the frame response
slave_FrameStatusHandler(slave, LinFrameStatusEvent{ timeEndOfFrame, slaveFrame, LinFrameStatus::LIN_TX_OK });

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Slave 1 Setup (Sender)
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup LinFrameResponseMode::TxUnconditional for LIN ID  0x11 on slave1
LinFrame slaveFrame;
slaveFrame.id = 0x11;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 1, 0, 0};
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slave1->Init(slaveConfig);

// Register FrameStatusHandler to receive data
auto slave1_FrameStatusHandler = [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {
};
slave1->AddFrameStatusHandler(slave1_FrameStatusHandler);

// ------------------------------------------------------------
// Slave 2 Setup (Receiver)
LinControllerConfig slave2Config;
slave2Config.controllerMode = LinControllerMode::Slave;
slave2Config.baudRate = 20000;

// Setup LinFrameResponseMode::Rx for LIN ID 0x11 on slave2
LinFrame slaveFrame;
slaveFrame.id = 0x11;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::Rx});

slave2->Init(slave2Config);

// Register FrameStatusHandler to receive data
auto slave2_FrameStatusHandler = [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {
};
slave2->AddFrameStatusHandler(slave2_FrameStatusHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

master->Init(masterConfig);

// Register FrameStatusHandler to receive confirmation of the successful transmission
auto master_FrameStatusHandler = [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {
};
master->AddFrameStatusHandler(master_FrameStatusHandler);

// ------------------------------------------------------------
// Perform TX from slave to slave, i.e., slave1 provides the response, slave2 receives it.
if (UseAutosarInterface)
{
    // AUTOSAR API
    LinFrame frameRequest;
    frameRequest.id = 0x11;
    frameRequest.checksumModel = LinChecksumModel::Enhanced;

    master->SendFrame(frameRequest, LinFrameResponseType::SlaveToSlave);
}
else
{
    // Alternative, non-AUTOSAR API
    master->SendFrameHeader(0x11);
}

// In both cases (AUTOSAR and non-AUTOSAR), the following callbacks will be triggered:
//  - TX confirmation for slave1, who provided the frame response
slave1_FrameStatusHandler(slave1, LinFrameStatusEvent{timeEndOfFrame, slave1Frame, LinFrameStatus::LIN_TX_OK});
//  - RX for slave2, who received the frame response
slave2_FrameStatusHandler(slave2, LinFrameStatusEvent{timeEndOfFrame, slave1Frame, LinFrameStatus::LIN_RX_OK});

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */

// ------------------------------------------------------------
// Slave Setup (Sender)
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup LinFrameResponseMode::TxUnconditional for LIN ID 0x10 and 0x11 on the slave
LinFrame slaveFrame;
slaveFrame.id = 0x10;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 0, 0, 0};
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slaveFrame.id = 0x11;
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slave->Init(slaveConfig);

// Register FrameStatusHandler to receive data
auto slave_FrameStatusHandler =
    [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
slave->AddFrameStatusHandler(slave_FrameStatusHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

// Also setup a TX Response for LIN ID 0x11 on the master (Errorneous Setup!)
LinFrame masterFrame;
masterFrame.id = 0x11;
masterFrame.dataLength = 8;
masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};
masterFrame.checksumModel = LinChecksumModel::Enhanced;
masterConfig.frameResponses.push_back(LinFrameResponse{masterFrame, LinFrameResponseMode::TxUnconditional});

master->Init(masterConfig);

// Register FrameStatusHandler to receive confirmation of the successful transmission
auto master_FrameStatusHandler =
    [](ILinController*, const LinFrameStatusEvent& frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

if (UseAutosarInterface)
{
    // Transmit the frame, slave has configured a TX Response for 0x10.
    LinFrame masterFrame;
    masterFrame.id = 0x10;
    masterFrame.checksumModel = LinChecksumModel::Enhanced;
    masterFrame.dataLength = 8;
    masterFrame.data = {'M', 'A', 'S', 'T', 'E', 'R', 0, 0};

    // AUTOSAR API
    master->SendFrame(masterFrame, LinFrameResponseType::MasterResponse);
}
else
{
    // Alternative, non-AUTOSAR API
    // Transmit the frame header, both master and slave have configured a TX Response for 0x11.
    master->SendFrameHeader(0x11);
}

// In both cases (AUTOSAR and non-AUTOSAR), the following callbacks will be triggered:
//  - LIN_TX_ERROR for the master and slave as both provided a response for the same LIN ID.
master_FrameStatusHandler(master, LinFrameStatusEvent{ timeEndOfFrame, masterFrame, LinFrameStatus::LIN_TX_ERROR });
slave_FrameStatusHandler(slave, LinFrameStatusEvent{ timeEndOfFrame, masterFrame, LinFrameStatus::LIN_TX_ERROR });

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Slave Setup
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

slave->Init(slaveConfig);

// Register FrameStatusHandler
auto slave_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
slave->AddFrameStatusHandler(slave_FrameStatusHandler);

// NOTE: No TX response is configured for the slave

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

master->Init(masterConfig);

// Register FrameStatusHandler to receive data from the LIN slave
auto master_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

// ------------------------------------------------------------
// Perform TX from slave to master, i.e., the slave /is expected/
// to provide the frame response.
if (UseAutosarInterface)
{
    // Use AUTOSAR interface to initiate the transmission.
    LinFrame frameRequest;
    frameRequest.id = 0x11;
    frameRequest.checksumModel = LinChecksumModel::Enhanced;

    master->SendFrame(frameRequest, LinFrameResponseType::SlaveResponse);
}
else
{
    // Alternative, non-AUTOSAR API
    // Transmit the frame header.
    master->SendFrameHeader(0x11);
}

// ------------------------------------------------------------
// The following master callback will be triggered:
//  - LIN_RX_NO_RESPONSE for the master, since no slave did provide a response
master_FrameStatusHandler(master, LinFrameStatusEvent{ timeEndOfFrame, frameRequest, LinFrameStatus::LIN_RX_NO_RESPONSE });
//  The slave_FrameStatusHandler will not be called!

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */

// ------------------------------------------------------------
// Slave 1 Setup (Sender)
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup LinFrameResponseMode::TxUnconditional for LIN ID 0x11 on slave1
LinFrame slaveFrame;
slaveFrame.id = 0x11;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 1, 0, 0};
slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

slave1->Init(slaveConfig);

// Register FrameStatusHandler to receive data
auto slave1_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
slave1->AddFrameStatusHandler(slave1_FrameStatusHandler);

// ------------------------------------------------------------
// Slave 2 Setup (Second Sender)
LinControllerConfig slave2Config;
slave2Config.controllerMode = LinControllerMode::Slave;
slave2Config.baudRate = 20000;

// Also setup LinFrameResponseMode::TxUnconditional for LIN ID 0x11 on slave2
LinFrame slaveFrame2;
slaveFrame2.id = 0x11;
slaveFrame2.checksumModel = LinChecksumModel::Enhanced;
slaveFrame2.dataLength = 8;
slaveFrame2.data = {'S', 'L', 'A', 'V', 'E', 1, 0, 0};
slaveConfig2.frameResponses.push_back(LinFrameResponse{slaveFrame2, LinFrameResponseMode::TxUnconditional});

slave2->Init(slave2Config);

// Register FrameStatusHandler to receive data
auto slave2_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
slave2->AddFrameStatusHandler(slave2_FrameStatusHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

master->Init(masterConfig);

// Register FrameStatusHandler to receive confirmation of the successful transmission
auto master_FrameStatusHandler =
    [](ILinController*,  const LinFrameStatusEvent& frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

// ------------------------------------------------------------
// Perform TX from slave to master, i.e., only one slave /is/
// /expected/ to provide the frame response. However, both
// slave1 and slave2 have done so.

if (UseAutosarInterface)
{
    // Use AUTOSAR interface to initiate the transmission.
    LinFrame frameRequest;
    frameRequest.id = 0x11;
    frameRequest.checksumModel = LinChecksumModel::Enhanced;

    master->SendFrame(frameRequest, LinFrameResponseType::SlaveResponse);
}
else
{
    // Alternative, non-AUTOSAR API
    master->SendFrameHeader(0x11);
}

// ------------------------------------------------------------
// The following callbacks will be triggered:
//  - LIN_RX_ERROR for the master, due to the collision 
master_FrameStatusHandler(master, LinFrameStatusEvent{ timeEndOfFrame, frameRequest, LinFrameStatus::LIN_RX_ERROR });
//  - LIN_TX_ERROR for both slaves
slave1_FrameStatusHandler(slave1, LinFrameStatusEvent{timeEndOfFrame, frameRequest, LinFrameStatus::LIN_TX_ERROR});
slave2_FrameStatusHandler(slave2, LinFrameStatusEvent{timeEndOfFrame, frameRequest, LinFrameStatus::LIN_TX_ERROR});

Go To Sleep

This example shows how to use GoToSleep() and when the controller will switch from operational to sleep mode.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Slave Setup
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

slave->Init(slaveConfig);

// Register FrameStatusHandler to receive data
auto slave_FrameStatusHandler =
    [](ILinController*, const LinFrameStatusEvent frameStatusEvent) {};
slave->AddFrameStatusHandler(slave_FrameStatusHandler);

// Set sleep mode for the slave upon reception of a GoToSleep Frame
auto slave_GoToSleepHandler =
    [](ILinController* slave, const LinGoToSleepEvent& goToSleepEvent) { 
    slave->GoToSleepInternal(); 
};
slave->AddGoToSleepHandler(slave_GoToSleepHandler);

// ------------------------------------------------------------
// Master Setup
LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;

master->Init(masterConfig);

// Register FrameStatusHandler to receive confirmation of the successful transmission
auto master_FrameStatusHandler =
    [](ILinController*, const LinFrameStatusEvent frameStatusEvent) {};
master->AddFrameStatusHandler(master_FrameStatusHandler);

// ------------------------------------------------------------
// Send a GoToSleep Frame to the LIN bus
master->GoToSleep();

// The master will enter sleep state immediately, i.e., the following condition is true:
assert(master->Status() == LinControllerStatus::Sleep);

// The slave will receive the go-to-sleep frame and trigger the callback:
slave_GoToSleepHandler(goToSleepEvent);

// the registered callback sets sleep state for the slave, after which also the slave is in sleep state:
assert(slave->Status() == LinControllerStatus::Sleep);

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Register a wake up handler. To receive wake up notifications.
// NB: this should be done when creating the controller!
// NB: receiving a wake up pulse does not automatically
//     set the controller into operational state
auto master_WakeupHandler = [](ILinController* master, LinWakeupEvent wakeupEvent) { master->WakeupInternal(); };
master->AddWakeupHandler(master_WakeupHandler);

// ------------------------------------------------------------
// Send a wake up pulse to the LIN bus
slave->Wakeup();

// The slave will immediately enter operational state:
assert(slave->Status() == LinControllerStatus::Operational);

// The master will receive the wake up pulse and the registered callback is
// triggered by the controller:
master_WakeupHandler(LinWakeupEvent{ timestamp, master } );

// The registered callback puts the master back into operational state, i.e.:
assert(master->Status() == LinControllerStatus::Operational);

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.

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// 
// Master Setup
using namespace SilKit::Services::Lin;
using namespace SilKit::Experimental::Services::Lin;

LinControllerConfig masterConfig;
masterConfig.controllerMode = LinControllerMode::Master;
masterConfig.baudRate = 20000;
master->Init(masterConfig);

// Define the LinSlaveConfigurationHandler
auto LinSlaveConfigurationHandler =
    [](ILinController* master, LinSlaveConfigurationEvent frameResponseUpdateEvent) 
{
    // aggregatedSlaveConfig will contain
    // LinSlaveConfiguration::respondingLinIds{ 0x11 }
    auto aggregatedSlaveConfig = GetSlaveConfiguration(master);
};

AddLinSlaveConfigurationHandler(master, &LinSlaveConfigurationHandler);

// ------------------------------------------------------------
// Slave Setup
LinControllerConfig slaveConfig;
slaveConfig.controllerMode = LinControllerMode::Slave;
slaveConfig.baudRate = 20000;

// Setup a TX Response for LIN ID 0x11
LinFrame slaveFrame;
slaveFrame.id = 0x11;
slaveFrame.checksumModel = LinChecksumModel::Enhanced;
slaveFrame.dataLength = 8;
slaveFrame.data = {'S', 'L', 'A', 'V', 'E', 0, 0, 0};

slaveConfig.frameResponses.push_back(LinFrameResponse{slaveFrame, LinFrameResponseMode::TxUnconditional});

// LinSlaveConfigurationHandler handler is invoked
slave->Init(slaveConfig);

The experimental API is defined as follows:

auto SilKit::Experimental::Services::Lin::AddLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController *linController, SilKit::Experimental::Services::Lin::LinSlaveConfigurationHandler handler) -> SilKit::Util::HandlerId

Add a LinSlaveConfigurationHandler on a given controller that triggers when a remote LIN slave is changes its configuration.

This callback is mainly for diagnostic purposes and is NOT needed for regular LIN controller operation. It can be used to call GetSlaveConfiguration to keep track of LIN Ids, where a response of a LIN Slave is to be expected.

Requires Services::Lin::LinControllerMode::Master.

Parameters
  • linController – The LIN controller to add the handler.

  • handler – The callback that is triggered upon a configuration update.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

void SilKit::Experimental::Services::Lin::RemoveLinSlaveConfigurationHandler(SilKit::Services::Lin::ILinController *linController, SilKit::Util::HandlerId handlerId)

Remove a LinSlaveConfigurationHandler by HandlerId on a given controller.

Requires Services::Lin::LinControllerMode::Master.

Parameters
  • linController – The LIN controller to remove the handler.

  • handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

auto SilKit::Experimental::Services::Lin::GetSlaveConfiguration(SilKit::Services::Lin::ILinController *linController) -> SilKit::Experimental::Services::Lin::LinSlaveConfiguration

Get the aggregated response configuration of all LIN slaves in the network.

Requires Services::Lin::LinControllerMode::Master.

Parameters

linController – The LIN controller (master) to providing the view.

Returns

A struct containing all LinIds on which LIN Slaves have configured Services::Lin::LinFrameResponseMode::TxUnconditional.