CAN Service API

Using the CAN Controller

The CAN Service API provides a CAN bus abstraction through the ICanController interface. A CAN controller is created by calling CreateCanController given a controller name and network name:

auto* canController = participant->CreateCanController("CAN1", "CAN");

CAN controllers will only communicate within the same network.

Sending CAN Frames

Data is transferred in the form of a CanFrame and received as a CanFrameEvent. To send a CanFrame, it must be setup with a CAN ID and the data to be transmitted. Furthermore, valid CanFrame::CanFrameFlag have to be set:

// Prepare a CAN message with id 0x17
CanFrame canFrame;
canFrame.canId = 3;
canFrame.flags = static_cast<CanFrameFlagMask>(CanFrameFlag::Fdf)  // FD Format Indicator
               | static_cast<CanFrameFlagMask>(CanFrameFlag::Brs); // Bit Rate Switch (for FD Format only)
canFrame.dataField = {'d', 'a', 't', 'a', 0, 1, 2, 3};

canController.SendFrame(canFrame);

Transmission Acknowledgement

To be notified of the success or failure of the transmission, a FrameTransmitHandler can be registered using AddFrameTransmitHandler():

auto frameTransmitHandler = [](ICanController*, const CanFrameTransmitEvent& frameTransmitEvent)
{
  // Handle frameTransmitEvent
};
canController->AddFrameTransmitHandler(frameTransmitHandler);

An optional second parameter of AddFrameTransmitHandler() allows to specify the status (CanTransmitStatus::Transmitted, …) of the CanFrameTransmitEvent to be received. By default, each status is enabled.

Note

In a simple simulation without the network simulator, the CanTransmitStatus of the CanFrameTransmitEvent will always be CanTransmitStatus::Transmitted. If a detailed simulation is used, it is possible that the transmit queue overflows causing the handler to be called with CanTransmitStatus::TransmitQueueFull signaling a transmission failure.

Receiving CAN Frame Events

A CanFrame is received as a CanFrameEvent consisting of a transmitId used to identify the acknowledgment of the frame, a timestamp and the actual CanFrame. The handler is called whenever a CanFrame is received:

auto frameHandler = [](ICanController*, const CanFrameEvent& frameEvent)
{
  // Handle frameEvent
};
canController->AddFrameHandler(frameHandler);

An optional second parameter of AddFrameHandler() allows to specify the direction (TX, RX, TX/RX) of the CAN frames to be received. By default, only frames of RX direction are handled.

Receiving State Change Events

To receive changes of the CanControllerState, a StateChangeHandler must be registered using AddStateChangeHandler():

auto stateChangedHandler = [](ICanController*, const CanStateChangeEvent& stateChangeEvent)
{
  // Handle stateChangeEvent;
};
canController->AddStateChangeHandler(stateChangedHandler);

Similarly, changes in the CanErrorState can be tracked with AddErrorStateChangeHandler().

Initialization

A CAN controller’s baud rate must first be configured by passing a value to ICanController::SetBaudRate(). Then, the controller must be started explicitly by calling Start(). Now the controller can be used. Additional control commands are Stop() and Reset().

The following example configures a CAN controller with a baud rate of 10’000 baud for regular CAN messages and a baud rate of 1’000’000 baud for CAN FD messages. Then, the controller is started:

canController->SetBaudRate(10000, 1000000);
canController->Start();

Note

Both ICanController::SetBaudRate() and Start() should not be called earlier than in the lifecycle service’s communication ready handler. Otherwise, it is not guaranteed that all participants are already connected, which can cause the call to have no effect.

Managing the Event Handlers

Adding a handler will return a HandlerId. This ID can be used to remove the handler via:

API and Data Type Reference

CAN Controller API

class ICanController

Abstract CAN Controller API to be used by vECUs.

Public Types

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

Generic CAN callback method.

using FrameHandler = CallbackT<CanFrameEvent>

Callback type to indicate that a CanFrameEvent has been received. Cf., ICanController::AddFrameHandler(FrameHandler,DirectionMask);

using StateChangeHandler = CallbackT<CanStateChangeEvent>

Callback type to indicate that the CanControllerState has changed. Cf., ICanController::AddStateChangeHandler(StateChangeHandler);

using ErrorStateChangeHandler = CallbackT<CanErrorStateChangeEvent>

Callback type to indicate that the controller CanErrorState has changed. Cf., ICanController::AddErrorStateChangeHandler(ErrorStateChangeHandler);

using FrameTransmitHandler = CallbackT<CanFrameTransmitEvent>

Callback type to indicate that a CanFrameTransmitEvent has been received. Cf., ICanController::AddFrameTransmitHandler(FrameTransmitHandler,CanTransmitStatusMask);

Public Functions

virtual ~ICanController() = default
virtual void SetBaudRate(uint32_t rate, uint32_t fdRate, uint32_t xlRate) = 0

Configure the baud rate of the controller.

NB: The baud rate of a CAN controller must be set before using it.

NB: In a detailed simulation, the baud rate is used to calculate transmission delays of CAN messages and to determine proper configuration and interoperation of the connected controllers.

Parameters
  • rate – Baud rate for regular (non FD) CAN messages given in bps; valid range: 0 to 2’000’000

  • fdRate – Baud rate for CAN FD messages given in bps; valid range: 0 to 16’000’000

  • xlRate – Baud rate for CAN XL messages given in bps; valid range: 0 to 16’000’000

virtual void Reset() = 0

Reset the CAN controller.

Resets the controller’s Transmit Error Count (TEC) and the Receive Error Count (REC). Furthermore, sets the CAN controller state to CanControllerState::Uninit and the controller’s error state to CanErrorState::NotAvailable.

Start(), Stop(), Sleep()

virtual void Start() = 0

Start the CAN controller.

Reset(), Stop(), Sleep()

virtual void Stop() = 0

Stop the CAN controller.

Reset(), Start(), Sleep()

virtual void Sleep() = 0

Put the CAN controller in sleep mode.

Reset(), Start(), Stop()

virtual void SendFrame(const CanFrame &msg, void *userContext = nullptr) = 0

Request the transmission of a CanFrame.

NB: The CanFrame must provide a valid CAN ID and valid flags. The controller must be in the Started state to transmit and receive messages.

Parameters
  • msg – The frame to transmit.

  • userContext – An optional user provided pointer that is reobtained in the FrameTransmitHandler.

virtual auto AddFrameHandler(FrameHandler handler, DirectionMask directionMask = (DirectionMask)TransmitDirection::RX) -> HandlerId = 0

Register a callback for CAN message reception.

The registered handler is called when the controller receives a new CanFrame.

Returns

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

virtual void RemoveFrameHandler(HandlerId handlerId) = 0

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

Parameters

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

virtual auto AddStateChangeHandler(StateChangeHandler handler) -> HandlerId = 0

Register a callback for controller state changes.

The registered handler is called when the SilKit::Services::Can::CanControllerState of the controller changes. E.g., after starting the controller, the state changes from SilKit::Services::Can::CanControllerState::Uninit to SilKit::Services::Can::CanControllerState::Started.

Returns

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

virtual void RemoveStateChangeHandler(HandlerId handlerId) = 0

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

Parameters

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

virtual auto AddErrorStateChangeHandler(ErrorStateChangeHandler handler) -> HandlerId = 0

Register a callback for changes of the controller’s error state.

The registered handler is called when the SilKit::Services::Can::CanErrorState of the controller changes. During normal operation, the controller should be in state SilKit::Services::Can::CanErrorState::ErrorActive. The states correspond to the error state handling protocol of the CAN specification.

NB: Only supported in a detailed simulation. In simple simulation, the handler is never called.

Returns

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

virtual void RemoveErrorStateChangeHandler(HandlerId handlerId) = 0

Remove an ErrorStateChangeHandler by SilKit::Util::HandlerId on this controller.

Parameters

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

virtual auto AddFrameTransmitHandler(FrameTransmitHandler handler, CanTransmitStatusMask statusMask = SilKit_CanTransmitStatus_DefaultMask) -> HandlerId = 0

Register a callback for the TX status of sent CAN messages.

The registered handler is called when a CAN message was successfully transmitted on the bus or when an error occurred.

NB: Full support in a detailed simulation. In a simple simulation, all messages are automatically positively acknowledged.

virtual void RemoveFrameTransmitHandler(HandlerId handlerId) = 0

Remove a FrameTransmitHandler 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 CanFrame

A CAN Frame.

Public Members

uint32_t canId

CAN Identifier.

CanFrameFlagMask flags

CAN Arbitration and Control Field Flags

uint16_t dlc

Data Length Code - describes the length of the dataField The acceptable bit-patterns and their semantics differ between CAN, CAN FD and CAN XL. The user is responsible for setting this field correctly. Please consult the CAN specifications for further information.

uint8_t sdt

SDU type - describes the structure of the frames Data Field content (for XL Format only)

uint8_t vcid

Virtual CAN network ID (for XL Format only)

uint32_t af

Acceptance field (for XL Format only)

Util::Span<const uint8_t> dataField

The raw CAN data field.

struct CanFrameEvent

The event of an incoming CAN frame including transmit ID, timestamp and the actual frame.

Public Members

std::chrono::nanoseconds timestamp

Send time.

CanFrame frame

The incoming CAN Frame.

TransmitDirection direction

Receive/Transmit direction.

void *userContext

Optional pointer provided by user when sending the frame.

struct CanFrameTransmitEvent

The acknowledgment of a CAN message, sent to the controller.

Public Members

uint32_t canId

Identifies the CAN id to which this CanFrameTransmitEvent refers to.

std::chrono::nanoseconds timestamp

Timestamp of the CAN acknowledge.

CanTransmitStatus status

Status of the CanTransmitRequest.

void *userContext

Optional pointer provided by user when sending the frame.

struct CanStateChangeEvent

An incoming state change event.

Public Members

std::chrono::nanoseconds timestamp

Timestamp of the state change.

CanControllerState state

The new state.

struct CanErrorStateChangeEvent

An incoming error state change event.

Public Members

std::chrono::nanoseconds timestamp

Timestamp of the state change.

CanErrorState errorState

The new error state.

Enumerations and Typedefs

enum SilKit::Services::Can::CanControllerState

CAN Controller state according to AUTOSAR specification AUTOSAR_SWS_CANDriver 4.3.1.

Values:

enumerator Uninit

CAN controller is not initialized (initial state after reset).

enumerator Stopped

CAN controller is initialized but does not participate on the CAN bus.

enumerator Started

CAN controller is in normal operation mode.

enumerator Sleep

CAN controller is in sleep mode which is similar to the Stopped state.

enum SilKit::Services::Can::CanErrorState

Error state of a CAN node according to CAN specification.

Values:

enumerator NotAvailable

Error State is Not Available, because CAN controller is in state Uninit.

AUTOSAR Doc: Successful transmission.

enumerator ErrorActive

Error Active Mode, the CAN controller is allowed to send messages and active error flags.

enumerator ErrorPassive

Error Passive Mode, the CAN controller is still allowed to send messages, but must not send active error flags.

enumerator BusOff

(currently not in use)

AUTOSAR Doc: Bus Off Mode, the CAN controller does not take part in communication.

enum SilKit::Services::Can::CanFrameFlag

Values:

enumerator Ide

Identifier Extension.

enumerator Rtr

Remote Transmission Request.

enumerator Fdf

FD Format Indicator.

enumerator Brs

Bit Rate Switch (for FD Format only)

enumerator Esi

Error State indicator (for FD Format only)

enumerator Xlf

XL Format Indicator.

enumerator Sec

Simple Extended Content (for XL Format only)

enum SilKit::Services::Can::CanTransmitStatus

Transfer status of a CAN node according to CAN specification.

Values:

enumerator Transmitted

The message was successfully transmitted on the CAN bus.

enumerator Canceled

The transmit queue was reset. (currently not in use)

enumerator TransmitQueueFull

The transmit request was rejected, because the transmit queue is full.

Usage Examples

This section contains complete examples that show the usage of the CAN controller and the interaction of two or more controllers. Although the CAN controllers would typically belong to different participants and reside in different processes, their interaction is shown sequentially to demonstrate cause and effect.

Assumptions:

  • Variables canReceiver and canSender are of type ICanController.

  • All CAN controllers use the same CAN network.

Simple CAN Sender / Receiver Example

This example shows a successful data transfer from one CAN controller to another CAN controller connected on the same CAN network.

/* 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. */
// ------------------------------------------------------------
// Receiver Setup
canReceiver->SetBaudRate(10000, 1000000, 1000000);
canReceiver->Start();

// Register CanFrameHandler to receive data
auto receiver_frameHandler = [](ICanController*, const CanFrameEvent& frameEvent) {};
canReceiver->AddFrameHandler(receiver_frameHandler);

// ------------------------------------------------------------
// Sender Setup
canSender->SetBaudRate(10000, 1000000, 1000000);
canSender->Start();

// Register FrameTransmitHandler to receive acknowledge of the successful transmission
auto sender_frameTransmitHandler = [](ICanController*, const CanFrameTransmitEvent& frameTransmitEvent) {};
canSender->AddFrameTransmitHandler(sender_frameTransmitHandler);

// ------------------------------------------------------------
// Send message on CAN bus "CAN1".
const std::vector<uint8_t> canFrameData = {'d', 'a', 't', 'a', 0, 1, 2, 3};
CanFrame canFrame{};
canFrame.canId = 17;
canFrame.flags =
    // FD Format Indicator
      static_cast<CanFrameFlagMask>(CanFrameFlag::Fdf)
    // Bit Rate Switch  (for FD Format only)
    | static_cast<CanFrameFlagMask>(CanFrameFlag::Brs);
canFrame.dataField = canFrameData;
canFrame.dlc = canFrame.dataField.size();

// The returned transmitId can be used to check if the canTransmitAcknowledge
// that should be triggered after a successful reception has the same transmitId
auto transmitId = canSender->SendFrame(canFrame);

// ------------------------------------------------------------
// The following callbacks will be triggered:
//  - TX confirmation for the sender. Only triggered once independently of the receiver count.
sender_frameTransmitHandler(canSender, frameTransmitEvent);
// with:
//  - frameTransmitEvent.transmitId == 1
//  - frameTransmitEvent.canId == 17
//  - frameTransmitEvent.timestamp = 
//  - frameTransmitEvent.status == CanTransmitStatus.Transmitted
//
//  - RX for the receiver or any other controller that is connected to the same CAN bus
//    except the sender of the CAN message
receiver_frameHandler(canReceiver, frameEvent);