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.
-
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.
-
using CallbackT = std::function<void(ICanController *controller, const MsgT &msg)>
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.
-
uint32_t canId
-
struct CanFrameEvent
The event of an incoming CAN frame including transmit ID, timestamp and the actual 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.
-
uint32_t canId
-
struct CanStateChangeEvent
An incoming state change event.
Public Members
-
std::chrono::nanoseconds timestamp
Timestamp of the state change.
-
CanControllerState state
The new state.
-
std::chrono::nanoseconds timestamp
-
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.
-
std::chrono::nanoseconds timestamp
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.
-
enumerator Uninit
-
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.
-
enumerator NotAvailable
-
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)
-
enumerator Ide
-
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.
-
enumerator Transmitted
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
andcanSender
are of typeICanController
.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);