Skip to content

Ethernet - Overview

API Documentation

feral.ethernet

The Ethernet module enables the simulation of full-duplex switched and unswitched (hub) ethernet networks.

Both models can be instantiated, configured, and integrated to a simulation scenario in the same way.

Note

Resource contention is not modeled. Two simultaneous transmissions will be serialized.

Jitter modeling is not supported.

Models

Switched Ethernet

The switched ethernet network module is an event-triggered FERAL worker. It simulates the usage of ethernet networks with store-and-forward switches.

Unswitched Ethernet

The unswitched ethernet network module is an event-triggered FERAL worker. It simulates the usage of ethernet networks with multicast.

Instantiation

To instantiate a switched or an unswitched ethernet network, one needs to provide the parent discrete-event MOCC and the number of nodes that the network should instantiate.

  • public SwitchedEthernetNetwork(Director parent, int networkInterfaces)
  • public UnswitchedEthernetNetwork(Director parent, int networkInterfaces)

The constructors automatically instantiate all the underlying objects and logics representing the topology, the ethernet coder, as well as the medium.

Ethernet Network Configuration

The ethernet models have two methods for their configuring:

  • public void setBitRate(long bitRateInBitsPerSecond)
  • public void setLogTransmissions(boolean logTransmissions)

If the transmissions are set to be logged (logTransmissions := true), the medium-level communications will be logged.

Info

The default bit-rate is set to 100Kbit/s. I.e., bitRateInBitsPerSecond := 100_000L.

Integrating an Ethernet Network with a Simulation Scenario

Independently of the type of ethernet network that one needs to simulate, the steps are the same. A possible sequence of steps is presented below:

  1. Instantiate the SimulationScenario and Director objects.
  2. Instantiate the communicating parties.
  3. Instantiate and configure the ethernet network.
  4. Define the network message types by means of the network interfaces.
  5. Link the network interfaces with the respective FERAL workers.
  6. Start the simulation execution.

Ethernet Network Model Examples

The examples below present distinct ways and APIs to use the ethernet network model.

This example depicts a single process Java simulation with a sender and a receiver communicating via an unswitched ethernet network.

EthernetExampleScenario.java
public class EthernetExampleScenario {
    // ... Declare and instantiate class and instance variables as necessary
    final SimulationDuration SEND_INTERVAL_MS = SimulationDuration._1MS.mul(10);
    // ...

    public main(String[] args) {
        // 1. Instantiate SimulationScenario and Director objects
        Scenario simulationScenario = new SimulationScenario();
        Director director = new DiscreteEventMOCC("Root Director", simulationScenario);

        // 2. Instantiate the communicating parties
        // The sending interval being null indicates the class should be a pure receiver
        CommunicatingEventWorker ethSender = new CommunicatingEventWorker(director, SEND_INTERVAL_MS);
        CommunicatingEventWorker ethReceiver = new CommunicatingEventWorker(director);

        // 3. Instantiate and configure the network
        // Alternatively instantiate the SwitchedEthernetNetwork
        Network network = new UnswitchedEthernetNetwork(director, 2);

        // Set the desired bit-rate and logging behaviour
        network.setBitRate(100_000L); // 100kbit/s
        network.setLogTransmissions(true);

        // 4. Define the network's message types for each interface
        // Each interface will correspond to a communicating party as soon as we link it in step 5
        ApplicationInterface ethSenderInterface = network.getTopology().getApplicationInterface(0);
        ApplicationInterface ethReceiverInterface = network.getTopology().getApplicationInterface(1);

        // The messages sent to the provided network address will be forwarded to the set port
        // The port with the given name will be created within the network interface object
        // The ethernet simulation will use the set desired payload size to determine the reception time
        // Attention: the simulated payload size does not need to be realistic
        // Attention: note that we are setting Tx and Rx message types by means of the method call
        String networkAddress = "AABBCCDDEEFF";
        int simulatedPayloadBytes = CommunicatingEventWorker.messageSizeBytes;
        ethSenderInterface.addTxMessageType(networkAddress, "myInterfacePortName", simulatedPayloadBytes);
        ethReceiverInterface.addRxMessageType(networkAddress, "myInterfacePortName", simulatedPayloadBytes);

        // 5. Link the network and the communicating parties
        new Link(ethSender.getOutputPort("myOutputPort"), ethSenderInterface.getInputPort("myInterfacePortName"));
        new Link(ethReceiverInterface.getOutputPort("myInterfacePortName"), ethReceiver.getInputPort("myInputPort"))

        // 6. Start simulation execution
        simulationScenario.startSimulation(SIMULATION_DURATION);
    }
}

At the communicating FERAL workers, we have the following:

CommunicatingEventWorker.java
public class CommunicatingEventWorker extends EventTriggeredWorker {
    TxPort txPort = createOutputPort("myOutputPort");
    RxPort rxPort = createInputPort("myInputPort");

    SimulationDuration sendingInterval;

    // This object sends integers
    int myExampleMessage = 0;
    public static final messageSizeBytes = 4;

    // Timers always have a related object, which can be null
    // In this example, we are setting named timers
    enum TimerEventTypes {TIMER_INIT, TIMER_NEW_MESSAGE};

    public CommunicatingEventWorker(Director parent, SimulationDuration msgInterval) {
        super(parent);

        sendingInterval = msgInterval;
    }

    public CommunicatingEventWorker(Director parent) {
        this(parent, null);
    }

    @Override
    public void initialize() {
        if (sendingInterval != null) {
            // Component produces periodic events -> set first timer
            this.scheduleTimer(sendingInterval.getRawTimeNS(), TimerEventTypes.TIMER_INIT);
        }
    }

    @Override
    public void messageReceived(Event<? > timerEvent, RxPort rxPort) {
        // The value type must be known
        Integer receivedValue = (Integer) rxMsg.getValue();

        // Do something with the value
        // ...
    }

    @Override
    public void timerExpired(TimedEvent<?> timerEvent) {
        if (TimerEventTypes.TIMER_INIT.equals(timerEvent.getValue())) {
            myExampleMessage = 50;
        } else {
            myExampleMessage += 1;
        }

        Event<Long> txMsg = new ValueEvent<>(myExampleMessage);
        txPort.send(txMsg);

        // Component produces periodic events
        this.scheduleDeltaTimer(interval.getRawTimeNS(), TimerEventTypes.TIMER_NEW_MESSAGE);
    }

}

This example depicts the usage of the Ethernet model via the FERAL Gateway and Raw Interface. The simulation scenario is defined in Python, as well as the FERAL Gateway server. Two Java workers are then created for sending and receiving data.

Please, visit the respective documentation pages for more information on the Gateway and the Raw Interface API.

In the following scenarios, an ethernet network is set up with four nodes: two senders and two receivers. A sender-receiver pair link communicate via the legacy FERAL Native interface, and another sender-receiver pair link communicate via Flatbuffers using the SiLVI scheme. Each sender and receiver worker communicate via a specific port directing the data flow to the respective ethernet frame coder class.

EthernetScenario.py
    # This demo is to be executed together with the Sender and Receiver classes defined in Java under the package
    # de.fraunhofer.iese.feral.ext.pcc.fcapi.client.examples.raweth

    import feral3gp.feral as feral
    from feral3gp.feral import Simulation, millis, seconds, ETHConfig, ETHNodeConfig, MessageTypeConfig, \
            MessageType, EventTriggeredWorker, event, GatewayConfig, BackendConfig, set_log_level

    # 1. Configure the network
    ## Ethernet nodes configuration setup

    ### A sender Ethernet interface using the SiLVI mimetype
    eth_sender_silvi = ETHNodeConfig(
        name="eth_sender_silvi",
        is_raw=True,
        mime_type="application/vda.silvi.ethernet.flatbuffers.1",
        address="112233445566"
    )

    ### A sender Ethernet interface using the FERAL Native mimetype
    eth_sender_native = ETHNodeConfig(
        name="eth_sender_native",
        is_raw=True,
        mime_type="application/FERAL/Ethernet/Native-V1",
        address="334455667788"
    )

    ### A receiver Ethernet interface using the SiLVI mimetype
    eth_receiver_silvi = ETHNodeConfig(
        name="eth_receiver_silvi",
        is_raw=True,
        mime_type="application/vda.silvi.ethernet.flatbuffers.1",
        address="223344556677"
    )

    ### A receiver Ethernet interface using the FERAL Native mimetype
    eth_receiver_native = ETHNodeConfig(
        name="eth_receiver_native",
        is_raw=True,
        mime_type="application/FERAL/Ethernet/Native-V1",
        address="445566778899"
    )

    ## Ethernet network configuration setup
    ## Note: all the interface configurations of the participating network interfaces must be provided here
    eth_config = ETHConfig(
        bit_rate=100_000,
        name="My Ethernet network",
        log_transmissions=True,
        hexadecimal_payload_logging=False,
        nodes=[eth_sender_silvi, eth_sender_native, eth_receiver_silvi, eth_receiver_native]
    )

    # 2. Define the FERAL Gateway configuration
    ## Note: only one FERAL Gateway should be instantiated per scenario.
    ## Here, processes will communicate via UDP port 44444.
    gw_config = GatewayConfig(
        expected_clients=2,
        worker_ports=["senderPortSilvi", "senderPortNative", "receiverPortSilvi", "receiverPortNative"],
        backends=[BackendConfig(protocol=feral.TransmissionBackend.UDP, port=44444)],
        trigger_queue_size=None,
        name="My FERAL Gateway"
    )

    if __name__ == '__main__':
        set_log_level(feral.Loglevel.DEBUG)

        # 3. Instantiate the FERAL Gateway server based on the given configuration
        gw = feral.gateway(config=gw_config)

        # 4. Instantiate the Ethernet Network based on the given configuration
        eth = feral.ethernet(config=eth_config)

        # 5. Link the FERAL Gateway to the respective Ethernet Interfaces raw IO ports
        ## Note: the ports will be automatically instantiated and named "<node_name>_rawIO"
        ### Gateway -> ethernet network
        ### E.g., messages sent to "senderPortSilvi" will be forwarded to the "eth_sender_silvi" network interface.
        ### Senders will connect to these Gateway ports.
        feral.link(gw, "senderPortSilvi", eth, "eth_sender_silvi_rawIO")
        feral.link(gw, "senderPortNative", eth, "eth_sender_native_rawIO")
        ### Ethernet network -> Gateway
        ### E.g., messages sent from the ethernet "eth_receiver_silvi" network interface will be forwarded to 
        ### the Gateway port "receiverPortSilvi".
        ### Receivers will connect to these Gateway ports.
        feral.link(eth, "eth_receiver_silvi_rawIO", gw, "receiverPortSilvi")
        feral.link(eth, "eth_receiver_native_rawIO", gw, "receiverPortNative")

        # 6. Start the simulation
        ## Note: this line execution will result in a wait in the FERAL Gateway for the respective number of expected_clients.
        ## Execution of the scenario will continue when the clients successfuly connect.
        ## Note: The scenario will execute for 1 second of simulation time.
        feral.start(seconds(1))

The Sender class below demonstrates the connection to the FERAL Gateway, the creation of FERAL Native and SiLVI ethernet frames, as well as the sending via the FERAL Gateway Client.

Sender.java
    package de.fraunhofer.iese.feral.ext.pcc.fcapi.client.examples.raweth;

    import com.google.flatbuffers.FlatBufferBuilder;

    import de.fraunhofer.iese.feral.ext.pcc.fcapi.backend.TransmissionBackend;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.client.ClientControl;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.client.ClientException;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.coder.CoderTools;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.BufferDirection;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.BufferStatus;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.Frame;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.MessageTiming;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.MetaFrame;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.RegisterFile;
    import de.fraunhofer.iese.feral.ext.smd.comnet.wired.ethernet.frame.MacAddr;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.ClientConsole;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.Console;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.Loglevel;

    public class Sender {

        final static Loglevel LOGLEVEL = Loglevel.INFO;

        // The MAC addresses for the sender and receiver ethernet interfaces.
        final static String ETH0_SILVI_TX = "112233445566";
        final static String ETH1_SILVI_RX = "223344556677";
        final static String ETH2_NATIVE_TX = "334455667788";
        final static String ETH3_NATIVE_RX = "445566778899";

        // Simulation configuration variables
        final static long stepSize = 1_000_000;
        final static long firstSync = 0;

        // State variables
        static int msgCountNative = 0;
        static int msgCountSilvi = 0;

        static Console console;

        // Function for creating a SiLVI ethernet frame
        public static byte[] createSilviEthFrame(String srcMacAddress, String destMacAddress, byte[] payload) {

            FlatBufferBuilder builder = new FlatBufferBuilder();

            // Create EthernetFrame. Prepare first variables since nested object
            // serialization is not allowed

            int dataOffset = Frame.createDataVector(builder, payload);
            // - Prepare Source MAC address of the frame
            int srcMacOffset = Frame.createSrcMacVector(builder, new MacAddr(srcMacAddress).getMacAddress());
            // - Prepare Destination MAC address of the frame
            int destMacOffset = Frame.createDestMacVector(builder, new MacAddr(destMacAddress).getMacAddress());
            // - Start create Ethernet Frame
            Frame.startFrame(builder);
            Frame.addData(builder, dataOffset);
            Frame.addType(builder, 0x0800);
            Frame.addVlanTag(builder, 4711);
            Frame.addDestMac(builder, destMacOffset);
            Frame.addLength(builder, payload.length);
            Frame.addSrcMac(builder, srcMacOffset);

            int frameOffset = Frame.endFrame(builder);
            // Create MetaFrame (Ethernet Frame + Information from/to interface)
            // - Prepare timing (All in PS and all Simulation Time). Creation must be done
            // inline
            long sendRequestTimePS = 0L;
            long receptionTimePS = 0L;

            // - Start create Meta-Frame
            MetaFrame.startMetaFrame(builder);
            MetaFrame.addDirection(builder, BufferDirection.Tx);
            MetaFrame.addFrame(builder, frameOffset);
            MetaFrame.addStatus(builder, BufferStatus.None);

            MetaFrame.addTiming(builder,
                    MessageTiming.createMessageTiming(builder, sendRequestTimePS, 0L, receptionTimePS));
            int metaFrameOffset = MetaFrame.endMetaFrame(builder);

            int bufferOffset = RegisterFile.createBufferVector(builder, new int[] { metaFrameOffset });
            int registerFileOffset = RegisterFile.createRegisterFile(builder, bufferOffset);
            RegisterFile.finishSizePrefixedRegisterFileBuffer(builder, registerFileOffset);

            return builder.sizedByteArray();
        }

        // Function for creating a FERAL Native ethernet frame
        static void createNativeEthFrame(byte[] ethFrame, byte[] payload, String srcMac, String destMac) {
            CoderTools.setInt32(ethFrame, 0, 1); // interface id
            CoderTools.setInt32(ethFrame, 4, 3); // 3 for Eth
            CoderTools.setInt8(ethFrame, 8, 1);
            CoderTools.setInt8(ethFrame, 9, 1);
            CoderTools.setInt8(ethFrame, 10, 1); // Message version = 1
            CoderTools.setString(ethFrame, 11, srcMac); // source MAC address
            CoderTools.setString(ethFrame, 24, destMac); // destination MAC address

            CoderTools.setInt32(ethFrame, 37, 13); // Ethernet VLAN ID
            CoderTools.setInt16(ethFrame, 41, 2); // Ethernet frame type
            CoderTools.setInt16(ethFrame, 43, payload.length); // Payload length
            CoderTools.setByteArray(ethFrame, 47, payload, payload.length); // the payload of 4 bytes
        }

        public static void main(String[] args) throws ClientException {

            ClientControl client = new ClientControl(new ClientConsole(), TransmissionBackend.UDP);
            console = client.getConsole();
            console.setLogLevel(LOGLEVEL);

            // Client connection to the FERAL Gateway server ports
            // The Client will connect to the "senderPortSilvi" and "senderPortNative" using the respective mimetypes
            final int idSilvi = client.connect("localhost", 44444, "localhost", "senderPortSilvi",
                    "application/vda.silvi.ethernet.flatbuffers.1");
            final int idNative = client.connect("localhost", 44444, "localhost", "senderPortNative",
                    "application/FERAL/Ethernet/Native-V1");

            // Definition of payload values and creation of the Raw Interface ethernet frames
            final byte[] payloadNative = { 11, 22, 33, 44 };
            byte[] nativeFrame = new byte[payloadNative.length + 56];
            createNativeEthFrame(nativeFrame, payloadNative, ETH2_NATIVE_TX, ETH3_NATIVE_RX);

            final byte[] payloadSilvi = { 55, 66, 77, 88 };
            byte[] silviFrame = createSilviEthFrame(ETH0_SILVI_TX, ETH1_SILVI_RX, payloadSilvi);

            // Client commands for scenario querying and execution control
            long simulationDuration = client.getSimDuration(idNative);

            client.sync(idNative, firstSync);
            client.startSim(idNative);
            client.wait_(idNative);

            long time = client.getSimTime(idNative);

            // Synchronization and sending loop
            console.info("Starting send loop. This may take a while, depending on the step frequency...");
            while (true) {
                long newTime = time + stepSize;
                if (newTime > simulationDuration)
                    break;

                console.debug("Syncing to " + newTime + " / " + simulationDuration);
                client.sync(idNative, newTime);
                client.continue_(idNative);
                client.wait_(idNative);

                // Sending the feral native ETH frame
                console.debug("Sending native msg " + msgCountNative++);
                client.tx(idNative, nativeFrame);

                // Sending the silvi ETH frame
                console.debug("Sending silvi msg " + msgCountSilvi++);
                client.tx(idSilvi, silviFrame);

                time = client.getSimTime(idNative);
            }

            console.info("Sent native frames: " + (msgCountNative - 1));
            console.info("Sent silvi frames: " + (msgCountSilvi - 1));

            client.disconnectAll();
        }
    }

The Receiver class below demonstrates the connection to the FERAL Gateway and the creation of callbacks for the reception of FERAL Native and SiLVI ethernet frames.

Receiver.java
    package de.fraunhofer.iese.feral.ext.pcc.fcapi.client.examples.raweth;

    import java.nio.ByteBuffer;

    import com.google.flatbuffers.ByteBufferUtil;
    import com.google.flatbuffers.ByteVector;

    import de.fraunhofer.iese.feral.ext.pcc.fcapi.backend.TransmissionBackend;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.client.ClientControl;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.client.ClientControl.RxCbListener;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.client.ClientException;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.coder.CoderTools;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.Frame;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.MetaFrame;
    import de.fraunhofer.iese.feral.ext.pcc.fcapi.gateway.rawinterface.networkmodels.Ethernet.RegisterFile;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.ClientConsole;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.Console;
    import de.fraunhofer.iese.feral.krnl.scf.core.console.Loglevel;

    public class Receiver {

        final static Loglevel LOGLEVEL = Loglevel.INFO;

        // Simulation configuration variables
        final static long stepSize = 1_000_000;
        final static long firstSync = 0;

        // State variables
        static int msgCountSilvi = 0;
        static int msgCountNative = 0;

        static Console console;

        // Helper method to convert the received ByteVector Mac adresses to String
        static String byteVectorToString(ByteVector macAddrAsByteArr) {
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < macAddrAsByteArr.length(); i++) {
                buffer.append(Character.forDigit((macAddrAsByteArr.get(i) >> 4) & 0xF, 16));
                buffer.append(Character.forDigit((macAddrAsByteArr.get(i) & 0xF), 16));
            }
            return buffer.toString().toUpperCase();
        }

        // Callback function for receiving FERAL Native ethernet frames
        static RxCbListener rxCBNative = new RxCbListener() {
            @Override
            public void callback(int id, long simTime, byte[] data) {

                msgCountNative++;

                // receive frame
                byte[] ethFrame = data;
                String srcMac = CoderTools.getString(ethFrame, 11);
                String destMac = CoderTools.getString(ethFrame, 11 + srcMac.length() + 1);
                int payloadLength = CoderTools.getInt16(ethFrame,
                        11 + srcMac.length() + 1 + destMac.length() + 1 + 6);
                byte[] payload = CoderTools.getByteArray(ethFrame,
                        11 + srcMac.length() + 1 + destMac.length() + 1 + 10);

                console.debug(
                        "[FERAL Native ETH Receiver] received FERAL native ethernet frame on destination Mac adress "
                                + destMac
                                + " at simulation time " + simTime);

                for (int i = 0; i < payloadLength; i++) {
                    console.debug("[FERAL Native ETH Receiver] payload[" + i + "]: " + payload[i]);
                }

                return;
            }
        };

        // Callback function for receiving SiLVI ethernet frames
        static RxCbListener rxCBSilvi = new RxCbListener() {
            @Override
            public void callback(int id, long simTime, byte[] data) {

                msgCountSilvi++;

                // deserialize flatbuffer
                ByteBuffer buffer = ByteBufferUtil.removeSizePrefix(ByteBuffer.wrap(data));
                RegisterFile registerFile = RegisterFile.getRootAsRegisterFile(buffer);
                MetaFrame metaframe = registerFile.buffer(0);
                Frame frame = metaframe.frame();

                var srcMac = byteVectorToString(frame.srcMacVector());
                var destMac = byteVectorToString(frame.destMacVector());

                int payloadLength = frame.dataLength();

                byte[] payload = new byte[payloadLength];

                console.debug(
                        "[SILVI ETH Receiver] received SiLVI flatbuffers ethernet frame on destination Mac adress "
                                + destMac
                                + " at simulation time " + simTime);

                for (int i = 0; i < payloadLength; i++) {
                    payload[i] = frame.dataVector().get(i);
                    console.debug("[SILVI ETH Receiver] payload[" + i + "]: " + payload[i]);
                }

                return;
            }
        };

        public static void main(String[] args) throws ClientException {

            ClientControl client = new ClientControl(new ClientConsole(), TransmissionBackend.UDP);
            console = client.getConsole();
            console.setLogLevel(LOGLEVEL);

            // Client connection to the FERAL Gateway server ports
            // The Client will connect to the "receiverPortSilvi" and "receiverPortNative" using the respective mimetypes
            final int idSilvi = client.connect("localhost", 44444, "localhost", "receiverPortSilvi",
                    "application/vda.silvi.ethernet.flatbuffers.1");
            final int idNative = client.connect("localhost", 44444, "localhost", "receiverPortNative",
                    "application/FERAL/Ethernet/Native-V1");

            ;

            long simulationDuration = client.getSimDuration(idNative);

            client.sync(idNative, firstSync);

            // Register the callback methods
            client.rxCB(idNative, rxCBNative);
            client.rxCB(idSilvi, rxCBSilvi);

            client.startSim(idNative);
            client.wait_(idNative);

            long time = client.getSimTime(idNative);
            console.info("Receiving frames. This may take a while, depending on the step frequency...");
            while (true) {
                long newTime = time + stepSize;

                if (newTime > simulationDuration)
                    break;

                console.debug("syncing to " + newTime + " / " + simulationDuration);
                client.sync(idNative, newTime);
                client.continue_(idNative);
                client.wait_(idNative);

                time = client.getSimTime(idNative);
            }

            console.info("Received native frames: " + msgCountNative);
            console.info("Received silvi frames: " + msgCountSilvi);

            client.disconnectAll();
        }
    }