Custom Network Simulator

With the Network Simulator API, a custom network simulation for CAN, LIN, Ethernet or Flexray is made accessible. The core concept is that all controller communication is redirected to a network simulator participant who performs the detailed simulation and is responsible for the final message distribution. The scope of the Network Simulator API is to manage the message flow for incoming and outgoing messages, not to perform the simulation logic.

Warning

The Network Simulator API is experimental and might be changed or removed in future versions of the SIL Kit.

Using the Network Simulator API

The usage of the Network Simulator API can be split into a configuration- and a simulation phase. In the configuration phase, the Network Simulator defines the simulated networks while other participants create their controllers. The SIL Kit takes care of informing the Network Simulator about the emerging controllers. Vice versa, the controllers are informed that their network is simulated by the Network Simulator. The controllers on a simulated network will route their outgoing messages exclusively to the Network Simulator. Note that this behavior switch does not require any action on the participant that holds the controller. If the controller was configured with a network name that the Network Simulator defined as a simulated network, the new routing will take place automatically.

In the simulation phase, each message (e.g., controller configuration, frame requests) triggers a callback on the Network Simulator. These callbacks will drive the simulation implemented by the user. For outgoing messages, the Network Simulator API allows to produce events that can target individual controllers. E.g., a frame request will finally result in a frame transmission for all controllers and an acknowledge message for the triggering controller.

Configuration phase

The entry point of the Network Simulator API is the creation of an INetworkSimulator at a participant. Only one network simulator per participant is allowed:

INetworkSimulator* networkSimulator = SilKit::Experimental::Participant::CreateNetworkSimulator(participant.get());

On the INetworkSimulator instance, simulated networks can be registered. This affects controller of the given type in the whole SIL Kit simulation, if their configured network name and type matches.

auto mySimulatedCanNetwork = std::make_unique<MySimulatedCanNetwork>("CAN1");
networkSimulator->SimulateNetwork("CAN1", SimulatedNetworkType::CAN, std::move(mySimulatedCanNetwork));

The instance mySimulatedCanNetwork passed in SimulateNetwork represents a specific, named simulated network. The underlying class must inherit from the ISimulatedNetwork interface and must be implemented by the user of the Network Simulator API. Its purpose is twofold:

  1. Providing a producer object to send out messages to targeted controllers. This happens once per network by a a call from the SIL Kit to SetEventProducer(), here on the mySimulatedCanNetwork instance. In SetEventProducer(), an IEventProducer instance is handed over to the user. After casting to the specific event producer for the corresponding network type (e.g. to ICanEventProducer), the event producer can send targeted messages to the desired recipients.

void MySimulatedCanNetwork::SetEventProducer(std::unique_ptr<IEventProducer> eventProducer) {

    // Store the incoming event producer
    _eventProducer = std::move(eventProducer);
}

auto MySimulatedCanNetwork::GetCanEventProducer()
{
    // Cast and return the CAN event producer
    return static_cast<Can::ICanEventProducer*>(_eventProducer.get());
}
  1. Getting informed about emerging remote controllers and providing a target for the redirected communication (i.e. the simulated controller). This happens by calls from the SIL Kit to ProvideSimulatedController(), here on the mySimulatedCanNetwork instance, whenever a participant creates a controller. The method provides routing information to address the controller (i.e., the controller descriptor) and expects the user to return an instance that implements the ISimulatedController interface. For the different network types, one of the specific child classes (e.g., ISimulatedCanController for CAN networks) must be used. After providing the simulated controller, all messages from the original controller will be routed only to the Network Simulator and trigger message specific reception functions on the provided simulated controller instance. Other controllers will no longer receive the messages.

auto MySimulatedCanNetwork::ProvideSimulatedController(ControllerDescriptor controllerDescriptor) -> ISimulatedController*
{
    // Bookkeeping of the controller descriptors
    _controllerDescriptors.push_back(controllerDescriptor);

    // Store the simulated controllers
    _mySimulatedCanControllers.emplace_back(std::make_unique<MySimulatedCanController>(this, controllerDescriptor));

    // Return the interface pointer
    return _mySimulatedControllers.back().get();
}

The following graph shows the Network Simulator API usage of the configuration phase:

: Exemplary configuration phase of a network simulation

Figure 12 : Exemplary configuration phase of a network simulation.

Simulation phase

Via the provided implementation of an ISimulatedController in ProvideSimulatedController(), the user receives events generated by the original controller. An On...() callback exists for each possible message of a controller. E.g., if a remote controller on a simulated network intends to sends a CAN frame and calls SendFrame(), OnFrameRequest() is triggered on the ISimulatedCanController. The On...() callbacks represent the message input of the Network Simulator. For outgoing CAN messages, the Produce() methods from the ICanEventProducer can be used.

In the following code snippet, the simple simulation logic is to send out a CAN frame transmit event to the requesting controller and the actual CAN frame event as a broadcast to all controllers. Here, the IEventProducer was obtained in SetEventProducer() and is stored in MySimulatedCanNetwork. To target only the desired recipients, the receivers must be specified as a span of controller descriptors in all Produce() methods.

void MySimulatedCanController::OnFrameRequest(const CanFrameRequest& frameRequest)
{
    // Create the transmit acknowledge for the sending CAN controller
    Services::Can::CanFrameTransmitEvent ack;
    ack.canId = frameRequest.frame.canId;
    ack.status = Services::Can::CanTransmitStatus::Transmitted;
    ack.timestamp = _scheduler->Now(); // The custom scheduler has knowledge about the virtual simulation time
    ack.userContext = frameRequest.userContext;

    // Define the single receiver (the remote controller)
    std::array<ControllerDescriptor, 1> singleReceiverArray{_controllerDescriptor};
    auto singleReceiver = SilKit::Util::MakeSpan(singleReceiverArray);

    // Produce the transmit acknowledge event
    _mySimulatedCanNetwork->GetCanEventProducer()->Produce(std::move(ack), singleReceiver);

    // Distribute the frame to all controllers
    Services::Can::CanFrameEvent frameEvent;
    frameEvent.direction = Services::TransmitDirection::RX;
    frameEvent.frame = frameRequest.frame;
    frameEvent.timestamp = _scheduler->Now();
    frameEvent.userContext = frameRequest.userContext;
    std::vector<uint8_t> payloadBytes{frameRequest.frame.dataField.begin(), frameRequest.frame.dataField.end()};
    frameEvent.frame.dataField = SilKit::Util::ToSpan(payloadBytes);

    // Produce the actual frame event
    _mySimulatedNetwork->GetCanEventProducer()->Produce(frameEvent, _mySimulatedNetwork->GetAllReceivers());
}

The following graph shows the corresponding event flow and Network Simulator API for the code snippet:

: Exemplary simulation phase of a network simulation

Figure 13 : Exemplary simulation phase of a network simulation.

See the Network Simulator Demo for a complete example with class definitions and a custom scheduler.

Handling simulation time

A central use case of a Network Simulator is to simulate detailed time behavior of a virtual bus network. Emulating network specific behavior is not part of the Network Simulator API and has to be implemented by the user. For a simulation with virtual time synchronization, this can be achieved by a custom scheduler. The scheduler is provided with time-related events in the Network Simulator and updates the simulation time in the SetSimulationStepHandler(). When the virtual time advances, the custom scheduler triggers the due events. Further, the scheduler can provide the current simulation time for the produced events as shown in the code snippets.

Integrating in the SIL Kit Lifecycle

Usually, a Network Simulator is integrated in setup with distributed participants that use a coordinated lifecycle. This means that it is mandatory to know beforehand which participants will take part in the simulation and that all participants agree on a starting point of the simulation. Although it is not enforced by the Network Simulator API, this is the recommended lifecycle operation mode for SIL Kit simulations with a Network Simulator. The central reason is that in using a coordinated lifecycle, the Network Simulator cannot miss any message sent by the controllers, especially initial configuration messages that are essential to perform the bus simulation. The following aspects have to be considered that the Network Simulator is guaranteed to receive all messages in the distributed setup without any restrictions to the starting order of the participants:

  • The Network Simulator and all participants that hold simulated controllers must use a coordinated lifecycle.

  • As a consequence, a System Controller must be used that knows all required participant names.

  • The Network Simulator must call Start() before starting his lifecycle via StartLifecycle().

  • The participants must not trigger any bus message before their lifecycle state reaches CommunicationReady. Read the documentation on Lifecycle Management for further details.

Event flow

During the simulation, the Network Simulator is notified about all relevant calls of the controllers in the On...() callbacks. The Produce() methods of the Network Simulator then trigger one or more handlers on the controller. The following diagrams show the connection between this event flow for the various bus systems.

: CAN event flow

Figure 14 : CAN event flow.

: Ethernet event flow

Figure 15 : Ethernet event flow.

: LIN event flow

Figure 16 : LIN event flow.

: FlexRay event flow

Figure 17 : FlexRay event flow.

API and Data Type Reference

NetworkSimulator API

class INetworkSimulator

Network Simulator interface to register simulated networks and to start the network simulation. A network simulator object can be obtained via SilKit::Experimental::Participant::CreateNetworkSimulator. Note that there can only be one network simulater per participant.

Public Functions

virtual ~INetworkSimulator() = default
virtual void SimulateNetwork(const std::string &networkName, SimulatedNetworkType networkType, std::unique_ptr<ISimulatedNetwork> simulatedNetwork) = 0

Register a simulated network. The network of the given name and type is subject to a detailed simulation whose logic is provided by the custom network simulator. Controllers with the same network name and type will no longer broadcast their outgoing messages to other controllers. Instead, the traffic is routed to the network simulator participant and will arrive on a ISimulatedController. Based on the incoming messages (e.g., a frame request), the simulation logic can be performed and outgoing events (e.g. acknowledgments, frames) can be produced.

Parameters
virtual void Start() = 0

Start the network simulation of all previously registered networks. Simulated networks registered via INetworkSimulator::SimulateNetwork will be informed about corresponding controllers in the simulation with calls to ISimulatedNetwork::ProvideSimulatedController. This holds true for remote controllers that have been created before the call to INetworkSimulator::Start. Internally, remote controllers are informed that they are now part of a detailed network simulation and will route their messages to the network simulator. See the documentation for further information about the usage within the SIL Kit Lifecyle in order not to miss any messages on the network simulator.

class ISimulatedNetwork

Interface for a simulated network. An instance of a class inheriting from this interface is passed to the SIL Kit via INetworkSimulator::SimulateNetwork. The interface functions are then invoked by the SIL Kit.

Public Functions

virtual ~ISimulatedNetwork() = default
virtual auto ProvideSimulatedController(ControllerDescriptor controllerDescriptor) -> ISimulatedController* = 0

Called when the API requires the implementation of a simulated controller. This happens when a controller is created on a simulated network. The network must be registered via SilKit::Experimental::NetworkSimulation::INetworkSimulator::SimulateNetwork beforehand. After a simulated controller is provided, messages sent by the original controller will triggers message specific callbacks on the simulated controller.

Parameters

controllerDescriptor – The identifier of a remote controller. Used to address a specific controller as receiver when using the eventProducer.

Returns

The implementation must return a valid pointer to a SilKit::Experimental::NetworkSimulation::ISimulatedController. Note that this interface is abstract, the underlying class must inherit from the appropriate network-specific interface (e.g. Can::ISimulatedCanController, Flexray::ISimulatedFlexRayController, etc.).

virtual void SimulatedControllerRemoved(ControllerDescriptor controllerDescriptor) = 0

Deregistration of a simulated controller. Called when the participant that owns the controller leaves the simulation.

Parameters

controllerDescriptor – The identifier of a remote controller.

virtual void SetEventProducer(std::unique_ptr<IEventProducer> eventProducer) = 0

Called once to provide an SilKit::Experimental::NetworkSimulation::IEventProducer. This happens when the first controller appears on a simulated network.

Parameters

eventProducer – Used to generate events for a given group of receivers. Note that this interface is abstract, the object must be cast to the specific interface for the underlying network type (Can::ICanEventProducer, Flexray::IFlexRayEventProducer, etc.).

class ISimulatedController

Base class of a simulated controller.

Subclassed by SilKit::Experimental::NetworkSimulation::Can::ISimulatedCanController, SilKit::Experimental::NetworkSimulation::Ethernet::ISimulatedEthernetController, SilKit::Experimental::NetworkSimulation::Flexray::ISimulatedFlexRayController, SilKit::Experimental::NetworkSimulation::Lin::ISimulatedLinController

Public Functions

virtual ~ISimulatedController() = default
class ISimulatedCanController : public SilKit::Experimental::NetworkSimulation::ISimulatedController

API for simulated CAN controllers. If a new CAN controller is created on a simulated network, an implementation of this interface can be provided in ISimulatedNetwork::ProvideSimulatedController. Messages generated by the original controller will be redirected to the simulated controller and trigger the On… callbacks.

Public Functions

virtual ~ISimulatedCanController() = default
virtual void OnSetBaudrate(const CanConfigureBaudrate &canConfigureBaudrate) = 0

Incoming CAN controller message. Triggered when a CAN controller calls SilKit::Services::Can::ICanController::SetBaudRate().

Parameters

canConfigureBaudrate – The configured baud rate of the controller.

virtual void OnFrameRequest(const CanFrameRequest &canFrameRequest) = 0

Incoming CAN controller message. Triggered when a CAN controller calls SilKit::Services::Can::ICanController::SendFrame().

Parameters

canFrameRequest – The CAN frame requested to be sent.

virtual void OnSetControllerMode(const CanControllerMode &canControllerMode) = 0

Incoming CAN controller message. Triggered when a CAN controller calls SilKit::Services::Can::ICanController::Start(), SilKit::Services::Can::ICanController::Stop(), SilKit::Services::Can::ICanController::Sleep() or SilKit::Services::Can::ICanController::Reset().

Parameters

canControllerMode – The new controller state.

class ISimulatedEthernetController : public SilKit::Experimental::NetworkSimulation::ISimulatedController

API for simulated Ethernet controllers. If a new Ethernet controller is created on a simulated network, an implementation of this interface can be provided in ISimulatedNetwork::ProvideSimulatedController. Messages generated by the original controller will be redirected to the simulated controller and trigger the On… callbacks.

Public Functions

virtual ~ISimulatedEthernetController() = default
virtual void OnFrameRequest(const EthernetFrameRequest &ethernetFrameRequest) = 0

Incoming Ethernet controller message. Triggered when a Ethernet controller calls SilKit::Services::Ethernet::IEthernetController::SendFrame.

Parameters

ethernetFrameRequest – The Ethernet frame requested to be sent.

virtual void OnSetControllerMode(const EthernetControllerMode &ethernetControllerMode) = 0

Incoming Ethernet controller message. Triggered when a Ethernet controller calls SilKit::Services::Ethernet::IEthernetController::Activate or . SilKit::Services::Ethernet::IEthernetController::Deactivate.

Parameters

ethernetControllerMode – The current Ethernet controller mode.

class ISimulatedLinController : public SilKit::Experimental::NetworkSimulation::ISimulatedController

API for simulated LIN controllers. If a new LIN controller is created on a simulated network, an implementation of this interface can be provided in ISimulatedNetwork::ProvideSimulatedController. Messages generated by the original controller will be redirected to the simulated controller and trigger the On… callbacks.

Public Functions

virtual ~ISimulatedLinController() = default
virtual void OnFrameRequest(const LinFrameRequest &linFrameRequest) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::SendFrame.

Parameters

linFrameRequest – The LIN frame requested to be sent.

virtual void OnFrameHeaderRequest(const LinFrameHeaderRequest &linFrameHeaderRequest) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::SendFrameHeader.

Parameters

linFrameHeaderRequest – A LIN frame header.

virtual void OnWakeupPulse(const LinWakeupPulse &linWakeupPulse) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::Wakeup.

Parameters

linWakeupPulse – The Wakeup pulse without any further data except the event timestamp.

virtual void OnControllerConfig(const LinControllerConfig &linControllerConfig) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::Init.

Parameters

linControllerConfig – The LIN controller configuration and frame response data.

virtual void OnFrameResponseUpdate(const LinFrameResponseUpdate &linFrameResponseUpdate) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::UpdateTxBuffer or SilKit::Services::Lin::ILinController::SendFrame.

Parameters

linFrameResponseUpdate – An update for the frame response data.

virtual void OnControllerStatusUpdate(const LinControllerStatusUpdate &linControllerStatusUpdate) = 0

Incoming LIN controller message. Triggered when a LIN controller calls SilKit::Services::Lin::ILinController::Wakeup, SilKit::Services::Lin::ILinController::WakeupInternal, SilKit::Services::Lin::ILinController::GoToSleep or SilKit::Services::Lin::ILinController::GoToSleepInternal.

Parameters

linControllerStatusUpdate – The new LIN controller status.

class ISimulatedFlexRayController : public SilKit::Experimental::NetworkSimulation::ISimulatedController

API for simulated FlexRay controllers. If a new FlexRay controller is created on a simulated network, an implementation of this interface can be provided in ISimulatedNetwork::ProvideSimulatedController. Messages generated by the original controller will be redirected to the simulated controller and trigger the On… callbacks.

Public Functions

virtual ~ISimulatedFlexRayController() = default
virtual void OnHostCommand(const FlexrayHostCommand &flexrayHostCommand) = 0

Incoming FlexRay controller message. Triggered when a FlexRay controller calls SilKit::Services::Flexray::IFlexrayController::Run(), SilKit::Services::Flexray::IFlexrayController::DeferredHalt(), SilKit::Services::Flexray::IFlexrayController::Freeze(), SilKit::Services::Flexray::IFlexrayController::AllowColdstart(), SilKit::Services::Flexray::IFlexrayController::Wakeup() or SilKit::Services::Flexray::IFlexrayController::AllSlots().

Parameters

flexrayHostCommand – An identifier of the host command.

virtual void OnControllerConfig(const FlexrayControllerConfig &flexrayControllerConfig) = 0

Incoming FlexRay controller message. Triggered when a FlexRay controller calls SilKit::Services::Flexray::IFlexrayController::Configure.

Parameters

flexrayControllerConfig – The FlexRay cluster parameters, node parameters and initial TX buffer configuration.

virtual void OnTxBufferConfigUpdate(const FlexrayTxBufferConfigUpdate &flexrayTxBufferConfigUpdate) = 0

Incoming FlexRay controller message. Triggered when a FlexRay controller calls SilKit::Services::Flexray::IFlexrayController::ReconfigureTxBuffer.

Parameters

flexrayTxBufferConfigUpdate – The index and the new configuration of a TX buffer .

virtual void OnTxBufferUpdate(const FlexrayTxBufferUpdate &flexrayTxBufferUpdate) = 0

Incoming FlexRay controller message. Triggered when a FlexRay controller calls SilKit::Services::Flexray::IFlexrayController::UpdateTxBuffer.

Parameters

flexrayTxBufferUpdate – The index and the new payload of a TX buffer.

Enumerations and Typedefs

enum SilKit::Experimental::NetworkSimulation::SimulatedNetworkType

Values:

enumerator Undefined
enumerator CAN
enumerator LIN
enumerator Ethernet
enumerator FlexRay