Click or drag to resize

ModuleEmulator Class

Represents a module emulator.
Inheritance Hierarchy
SystemObject
  Demo3D.PLC.Rockwell.EmulatorModuleEmulator

Namespace:  Demo3D.PLC.Rockwell.Emulator
Assembly:  PLC (in PLC.dll) Version: 15.0.2.11458
Syntax
C#
public sealed class ModuleEmulator : IModuleEmulator, 
	IDisposable

The ModuleEmulator type exposes the following members.

Properties
  NameDescription
Public propertyEventLock
An object that you can lock to serialize access to the module emulator script functions.
Public propertyIPAddress
IP address of the device.
Public propertyProperties
Properties set by the module emulator factory. Always null for RPI events.
Top
Methods
  NameDescription
Public methodAfterOutputs
Calls all IAfterOutputs events.
Public methodBeforeInputs
Calls all IBeforeInputs events.
Public methodComputeInputs
Public methodCopyFieldsToImage
Copies data from the Module Emulator fields into the module image.
Public methodCopyFieldsToImage(DeviceArea)
Copies data from the Module Emulator fields into the specified areas of the module image.
Public methodCopyImageToFields
Copies data from the module image into the Module Emulator fields and properties.
Public methodCopyImageToFields(DeviceArea)
Copies data from specified areas of the module image into the Module Emulator fields and properties.
Public methodStatic memberFindAuto(Object)
Find members with the AutoAttribute.
Public methodStatic memberFindAutoT(Object)
Find members with the AutoAttribute.
Public methodStatic memberFindOrInstall
Finds or installs a ModuleEmulator.
Public methodGetSystemTime
Returns the device system time.
Public methodStatic memberInstall
Installs a ModuleEmulator for a specified EDSInfo and connection point.
Public methodProcessOutputs
Calls all IProcessOutputs events.
Public methodScheduleAfter
Schedule an event.
Public methodScheduleAt
Schedule an event.
Top
Events
  NameDescription
Public eventStatic memberOnModuleEmulatorInstalled
Occurs when a new ModuleEmulator is installed.
Public eventStatic memberOnModuleEmulatorUninstalled
Occurs when a ModuleEmulator is uninstalled.
Top
Examples

The following example shows a simple 5094 IF8 Module Emulator

C#
using System;
using Demo3D.Common;
using Demo3D.Net.Protocols;
using Demo3D.PLC.Comms.CPF;
using Demo3D.PLC.Rockwell.Emulator;

namespace Examples.DeviceEmulation {
    /// <summary>
    /// 5094 IF8 device emulation.
    /// </summary>
    public class DE_5094_IF8 : IConstructRPI, IProcessOutputs {
        [Auto] ModuleEmulator moduleEmulator;
        [Auto] uint           p_RunIdle;
        uint                  runIdle;
        ISystemTime           systemTime;
        bool                  synchronized;

        class Channel : IComputeInputs, IBeforeInputs {
            readonly DE_5094_IF8 emulator;

            [Auto]      float c_LowEngineering;
            [Auto]      float c_HighEngineering;
            [Auto]      float c_LowSignal;
            [Auto]      float c_HighSignal;
            [Auto]      float i_Data;
            [Auto, RPI] short i_RollingTimestamp;
            [Auto]      float pi_Data;

            internal Channel(DE_5094_IF8 emulator) => this.emulator = emulator;

            // Called in response to updates from Emulate3D, to compute the values to send to the PLC.
            void IComputeInputs.ComputeInputs() {
                if (emulator.p_RunIdle == 0) return;  // PLC is disconnected or in program mode
                var signalRange      = c_HighSignal      - c_LowSignal;
                var engineeringRange = c_HighEngineering - c_LowEngineering;
                i_Data               = ((pi_Data - c_LowSignal) * (engineeringRange / signalRange)) + c_LowEngineering;
            }

            // Called in the IO process immediately before sending input to the PLC.
            void IBeforeInputs.BeforeInputs() {
                var isSynchronized = emulator.systemTime.IsSynchronized;
                i_RollingTimestamp = !isSynchronized ? (short)0 : (short)((emulator.systemTime.SystemTimeMicroseconds / 1000) & 0x7fff);
            }
        }

        [Auto] readonly Channel Ch00;
        [Auto] readonly Channel Ch01;
        [Auto] readonly Channel Ch02;
        [Auto] readonly Channel Ch03;
        [Auto] readonly Channel Ch04;
        [Auto] readonly Channel Ch05;
        [Auto] readonly Channel Ch06;
        [Auto] readonly Channel Ch07;

        // IO process construct method.
        void IConstructRPI.Construct(IComponentLogger logger) {
            systemTime = moduleEmulator.GetSystemTime();
        }

        void IProcessOutputs.ProcessOutputs() {
            if (p_RunIdle != runIdle) {
                runIdle = p_RunIdle;
                if (runIdle != 0) moduleEmulator.ComputeInputs();
            }
        }

        // Installs this device emulator into the Emulate3D device network emulator.
        public static IDisposable Install() {
            var if8  = new EDSInfo(DeviceVendor.Rockwell, DeviceType.RAMisc, productCode: 315, 0, 0);
            var mask = EDSMask.Vendor | EDSMask.DeviceType | EDSMask.ProductCode;

            return ModuleEmulator.Install(typeof(DE_5094_IF8), if8, mask);
        }
    }
}

The following example shows a simple 5094 OB16 Module Emulator

C#
using System;
using Demo3D.Common;
using Demo3D.PLC.Comms.CIP;
using Demo3D.PLC.Comms.CIP.Nodes;
using Demo3D.PLC.Comms.CPF;
using Demo3D.PLC.Rockwell.Emulator;

namespace Examples.DeviceEmulation {
    /// <summary>
    /// 5094 IF8 device emulation.
    /// </summary>
    public class DE_5094_OB16 : IConstructEmulator {
        [Auto] uint p_Status;
        [Auto] uint p_RunIdle;

        [AutoInstance(ClassID.TimeSync, 1)] TimeSync timeSync;

        class Point : IProcessOutputs {
            readonly DE_5094_OB16 emulator;

            bool  oldProgMode;
            bool  oldFaulted;
            ulong faultStartTime;
            bool  faultFinalState;

            [Auto] bool c_ProgMode;
            [Auto] bool c_ProgValue;
            [Auto] bool c_ProgramToFaultEn;
            [Auto] bool c_FaultMode;
            [Auto] bool c_FaultValue;
            [Auto] byte c_FaultValueStateDuration;
            [Auto] bool c_FaultFinalState;
            [Auto] bool i_Data;
            [Auto] bool o_Data;

            internal Point(DE_5094_OB16 emulator) => this.emulator = emulator;

            public void ProcessOutputs() {
                // determine the current state
                var faulted  = (emulator.p_Status & 1) == 0;
                var progMode = !faulted && emulator.p_RunIdle == 0;

                // if we faulted while in program mode, and c_ProgramToFaultEn is unset
                // then behave as if we're still in program mode
                if (faulted && oldProgMode && !c_ProgramToFaultEn) {
                    faulted  = false;
                    progMode = true;
                }

                if (faulted) {
                    // we're faulted
                    // don't bother timing if the timer already expired, c_FaultFinalStateDuration is Forever, or we have no clock
                    if (!faultFinalState && c_FaultValueStateDuration != 0 && (emulator.timeSync?.IsSynchronized ?? false)) {
                        var timeNow = emulator.timeSync.SystemTimeMicroseconds;

                        if (!oldFaulted) {
                            // we just faulted, start timing
                            faultStartTime = timeNow;
                        } else {
                            // we were already faulted, did the timer expire?
                            var diffSeconds = (timeNow - faultStartTime) / 1000000;
                            faultFinalState = diffSeconds >= c_FaultValueStateDuration;
                        }
                    }

                    // faultFinalState is set when the c_FaultFinalStateDuration timer expired
                    // otherwise if c_FaultMode, force the output to c_FaultValue
                    if (faultFinalState)   i_Data = c_FaultFinalState;
                    else if (!c_FaultMode) i_Data = c_FaultValue;

                } else {
                    // we're not faulted
                    faultFinalState = false;

                    if (progMode) {
                        // we're in program mode
                        // if c_ProgMode is unset, force the output to c_ProgValue
                        if (!c_ProgMode) i_Data = c_ProgValue;

                    } else {
                        // running ok
                        i_Data = o_Data;
                    }
                }

                // remember last state
                oldProgMode = progMode;
                oldFaulted  = faulted;
            }
        }

        [Auto] readonly Point Pt00;
        [Auto] readonly Point Pt01;
        [Auto] readonly Point Pt02;
        [Auto] readonly Point Pt03;
        [Auto] readonly Point Pt04;
        [Auto] readonly Point Pt05;
        [Auto] readonly Point Pt06;
        [Auto] readonly Point Pt07;
        [Auto] readonly Point Pt08;
        [Auto] readonly Point Pt09;
        [Auto] readonly Point Pt10;
        [Auto] readonly Point Pt11;
        [Auto] readonly Point Pt12;
        [Auto] readonly Point Pt13;
        [Auto] readonly Point Pt14;
        [Auto] readonly Point Pt15;

        public void Construct(MessageRouter module, IComponentLogger logger) {
            timeSync.PTPEnable = true;
        }

        // Installs this device emulator into the Emulate3D device network emulator.
        public static IDisposable Install() {
            var ob16 = new EDSInfo(DeviceVendor.Rockwell, DeviceType.GeneralPurposeDiscreteIO, productCode: 399, 0, 0);
            var mask = EDSMask.Vendor | EDSMask.DeviceType | EDSMask.ProductCode;

            return ModuleEmulator.Install(typeof(DE_5094_OB16), ob16, mask);
        }
    }
}
See Also