Custom Interfaces

realvirtual.io is open and you could implement your custom interfaces to external software and hardware. Usually, you are using C# interface API of the external software.

All interface scripts in realvirtual.io inherit from the base class InterfaceBaseClass.

Depending on the interface type you are developing your new interface should inherit directly from one of these classes (all of them inherit from InterfaceBaseClass)

InterfaceBaseClass

For interface with a fast API data exchange or a small amount of data where you don’t need multithreading because of performance and possible long data exchange cycle times.

InterfaceThreadedBaseClass

For multi-threaded interfaces where the data exchange with the external application is running in a parallel thread.

InterfaceSHMBaseclass

For interfaces using shared memory to communicate with the external application. You can define your own shared memory data structure by writing your own interface.

Methods each custom interface must implement

OpenInterface()

A method that will be called when the interface should connect. The base class is calling this in OnAwake. When the connection is successful OnConnected() must be called. If the connection is not successful OnDisconnected() should be called and an attempt to connect should be made later on.

After opening the interface this method should also update the signal list with this method: UpdateInterfaceSignals(ref NumberInputs, ref NumberOutputs);

This method will parse the underlying objects and create a pulic list of Interface Signals: public List InterfaceSignals

You should use this list of interface signals later on in your update method for the signals.

CloseInterface()

A method that will be called when the interface should connect. The base class is calling this in OnDestroy.

Awake()

This standard method is called before OpenInterface. Use this method for initializing your variables or setting your external references. If you use Awake in your Interface implementation you must call inside your Awake() base.Awake() so that the Game4automationBehavior Awake is also called. Please don’t connect the Interface in your Awake method and please don’t call OpenInterface yourself in the Awake method.

Update()

An Update Method should implement an automatically reconnecting in a certain period for example like this.

public virtual void Update()
     {
         if (reconnecting && (Time.time-_lastreconnect)>1)
             OpenInterface();
         if (IsConnected)
             UpdateSignals(); // only if signals are updated on the main thread
     }

Only for non-threaded interfaces, you should also implement in this method the Update of the Signals (like UpdateSignals()) in the example above.

Importing Signals

Each interface should implement a method and a button in the inspector to import the signals. This method should parse the signals on the interface and create (if not already there) new Signal objects as sub-objects under the interface.

To create a signal you should follow the following steps:

var signal = new InterfaceSignal();
signal.Name = "the symbold name you received from the interface"
signal.SymbolName = adsSymbol.Name;
signal.Direction = InterfaceSignal.DIRECTION.OUTPUT; // or InterfaceSignal.DIRECTION.INPUT
signal.OriginDataType = "original data type"; // original data type
signal.Type = InterfaceSignal.TYPE.INT // or other signal types depending on your interface signal
AddSignal(signal); // this will add a new signal object under the interface

Updating the signal values during simulation

How to update the signals for the inputs and outputs depends very much on your interface type you are developing. For example, if your interface is multi-threaded or if it is possible to observe (to receive an event) if the output values changed or not.

If available you should always prefer to subscribe with your interface API for changes of the values. Polling all variables on each cycle is usually not the best performing method, but it depends on the methods your selected interface API is providing. If the only way for receiving the values is cyclic polling you should implement this cyclic polling in a parallel thread by using the InterfaceThreadedBaseClass,

For PLCInputs you could subscribe for data changes on the signals like that:

if (signal.Direction == InterfaceSignal.DIRECTION.INPUT)
{
    signal.Signal.SignalChanged += OnPLCInputSignalChanged;
}

This will call the Method OnPLCInputSignalChanged each time realvirtual.io changes the signals and you can take care in this method to send the new values with the use of your interface api.

If you want to make a loop over all interface signals you can use the following blueprint. The list of interface signals must be created during connecting to the interface - see above :

foreach (var signal in InterfaceSignals)
{
  if (signal.Direction == InterfaceSignal.DIRECTION.OUTPUT)
                {
	..... and so on

Special methods for multi-threaded interfaces

If you inherit from InterfaceThreadedBaseClass you need to call base.OpenInterface() in your OpenInterface method. This will start the multi threaded communication thread:

public override void OpenInterface()
   {
       .. what you need to do for opening the interface
       base.OpenInterface();
   }

You need to do the same in your CloseInterface method:

public override void CloseInterface()
      {
          .... what you need to do to close the interface..

          base.CloseInterface();
}

By calling base.CloseInterface() the communication thread will be stopped.

protected override void CommunicationThreadUpdate()

This method will be called automatically by the InterfaceThreadedBaseClass. You should implement here everything that you need for reading and writing the inputs and outputs.

It is very important, that you can not write directly to Unity object in a parallel thread. This means that you should use a data structure to synchronize between the parallel thread and the Unity main task. Your thread will write into this data and in Unity’s update method you can take this data transfer the information to Unity objects. You can use the InterfaceSignal class or your own custom class which inherits from InterfaceSignal to do this. You can take a look into the S7-Interface which is implemented multi-threaded to have a blueprint for your own multi-threaded solution.

To prevent collissions between the main unity thread and your communication thread you should use this statement to lock your data structure im your communication thread:

lock (InterfaceSignals)
           {.....

protected override void CommunicationThreadUpdate()

This method will be called automatically by the InterfaceThreadedBaseClass. You should implement here everything that you need for reading and writing the inputs and outputs.

Methods each custom interface should call

OnConnected()

A method in the base class which is called each time the interface is connected successfully. This could be on simulation start or when a reconnection attempt is successful. By calling this method the signals and interface will be automatically shown as connected and the Connect Button in the runtime UI will become greed (it is white when not connected). The IsConnected boolean property will get true.

OnDisconnected()

A method in the base class that is called each time the interface is disconnected. This could be at the end of simulation or when a communication interruption is recognized. By calling this method the signals and interface will be automatically shown as disconnected and the Connect Button in the runtime UI will become white (it is green when connected). The IsConnected boolean property will get false.

© 2022 in2Sight GmbH https://realvirtual.io - All rights reserved. No part of this publication may be reproduced, distributed, or transmitted in any form or by any means, including printing, saving, photocopying, recording, or other electronic or mechanical methods, without the prior written permission of the publisher.

Last updated