Skip to main content

ScannerController Class

Namespace: GHIElectronics.TinyCLR.EthernetIP.Scanner · Assembly: GHIElectronics.TinyCLR.EthernetIP.Scanner

Runs the device as an EtherNet/IP Scanner (the client/originator side — the role that talks to PLCs, motor drives, or other EIP adapters). Pure C# implementation, no native interop.

public class ScannerController : IDisposable

Properties

TCPPort

public ushort TCPPort { get; set; }

TCP-Port of the Server

TargetUDPPort

public ushort TargetUDPPort { get; set; }

UDP-Port of the IO-Adapter - Standard is 0xAF12

OriginatorUDPPort

public ushort OriginatorUDPPort { get; set; }

UDP-Port of the Scanner - Standard is 0xAF12

IPAddress

public string IPAddress { get; set; }

IPAddress of the Ethernet/IP Device

RequestedPacketRate_O_T

public uint RequestedPacketRate_O_T { get; set; }

Requested Packet Rate (RPI) in Microseconds Originator -> Target for Implicit-Messaging (Default 0x7A120 -> 500ms)

RequestedPacketRate_T_O

public uint RequestedPacketRate_T_O { get; set; }

Requested Packet Rate (RPI) in Microseconds Target -> Originator for Implicit-Messaging (Default 0x7A120 -> 500ms)

O_T_OwnerRedundant

public bool O_T_OwnerRedundant { get; set; }

"1" Indicates that multiple connections are allowed Originator -> Target for Implicit-Messaging (Default: TRUE)

T_O_OwnerRedundant

public bool T_O_OwnerRedundant { get; set; }

"1" Indicates that multiple connections are allowed Target -> Originator for Implicit-Messaging (Default: TRUE)

O_T_VariableLength

public bool O_T_VariableLength { get; set; }

With a fixed size connection, the amount of data shall be the size of specified in the "Connection Size" Parameter. With a variable size, the amount of data could be up to the size specified in the "Connection Size" Parameter Originator -> Target for Implicit Messaging (Default: True (Variable length))

T_O_VariableLength

public bool T_O_VariableLength { get; set; }

With a fixed size connection, the amount of data shall be the size of specified in the "Connection Size" Parameter. With a variable size, the amount of data could be up to the size specified in the "Connection Size" Parameter Target -> Originator for Implicit Messaging (Default: True (Variable length))

O_T_Length

public ushort O_T_Length { get; }

The maximum size in bytes (only pure data without sequence count and 32-Bit Real Time Header (if present)) from Originator -> Target for Implicit Messaging (Default: 505)

T_O_Length

public ushort T_O_Length { get; }

The maximum size in bytes (only pure data woithout sequence count and 32-Bit Real Time Header (if present)) from Target -> Originator for Implicit Messaging (Default: 505)

O_T_ConnectionType

public ConnectionType O_T_ConnectionType { get; set; }

Connection Type Originator -> Target for Implicit Messaging (Default: ConnectionType.Point_to_Point)

T_O_ConnectionType

public ConnectionType T_O_ConnectionType { get; set; }

Connection Type Target -> Originator for Implicit Messaging (Default: ConnectionType.Multicast)

O_T_Priority

public Priority O_T_Priority { get; set; }

Priority Originator -> Target for Implicit Messaging (Default: Priority.Scheduled) Could be: Priority.Scheduled; Priority.High; Priority.Low; Priority.Urgent

T_O_Priority

public Priority T_O_Priority { get; set; }

Priority Target -> Originator for Implicit Messaging (Default: Priority.Scheduled) Could be: Priority.Scheduled; Priority.High; Priority.Low; Priority.Urgent

O_T_InstanceID

public byte O_T_InstanceID { get; set; }

Class Assembly (Consuming IO-Path - Outputs) Originator -> Target for Implicit Messaging

T_O_InstanceID

public byte T_O_InstanceID { get; set; }

Class Assembly (Producing IO-Path - Inputs) Target -> Originator for Implicit Messaging

O_T_IOData

public byte[] O_T_IOData { get; set; }

Provides Access to the Class 1 Real-Time IO-Data Originator -> Target for Implicit Messaging

T_O_IOData

public byte[] T_O_IOData { get; set; }

Provides Access to the Class 1 Real-Time IO-Data Target -> Originator for Implicit Messaging

O_T_RealTimeFormat

public RealTimeFormat O_T_RealTimeFormat { get; set; }

Used Real-Time Format Originator -> Target for Implicit Messaging (Default: RealTimeFormat.Header32Bit) Possible Values: RealTimeFormat.Header32Bit; RealTimeFormat.Heartbeat; RealTimeFormat.ZeroLength; RealTimeFormat.Modeless

T_O_RealTimeFormat

public RealTimeFormat T_O_RealTimeFormat { get; set; }

Used Real-Time Format Target -> Originator for Implicit Messaging (Default: RealTimeFormat.Modeless) Possible Values: RealTimeFormat.Header32Bit; RealTimeFormat.Heartbeat; RealTimeFormat.ZeroLength; RealTimeFormat.Modeless

AssemblyObjectClass

public byte AssemblyObjectClass { get; set; }

AssemblyObject for the Configuration Path in case of Implicit Messaging (Standard: 0x04)

ConfigurationAssemblyInstanceID

public byte ConfigurationAssemblyInstanceID { get; set; }

ConfigurationAssemblyInstanceID is the InstanceID of the configuration Instance in the Assembly Object Class (Standard: 0x01)

ConfigurationAssembly_Data

public byte[] ConfigurationAssembly_Data { get; set; }

ConfigurationAssemblyInstanceID is the InstanceID of the configuration Instance in the Assembly Object Class (Standard: 0x01)

ConfigurationAssemblyData_Length

public ushort ConfigurationAssemblyData_Length { get; }

ConfigurationAssemblyDataLength max 500

WriteConfiguration

public bool WriteConfiguration { get; set; }

ConfigurationAssemblyDataLength max 500

LastReceivedImplicitMessage

public DateTime LastReceivedImplicitMessage { get; set; }

Returns the Date and Time when the last Implicit Message has been received fŕom The Target Device Could be used to determine a Timeout. NOTE: this is a wall-clock timestamp (DateTime.Now) and breaks if the system clock jumps (NTP sync, DST, manual set). For timeout detection that must survive clock changes, read LastReceivedImplicitMessageTickCount instead and compare against Environment.TickCount.

LastReceivedImplicitMessageTickCount

public int LastReceivedImplicitMessageTickCount { get; set; }

Monotonic (clock-jump-safe) counterpart of LastReceivedImplicitMessage. Stores Environment.TickCount at the moment the last Class-1 packet was received from the target. Compare against a fresh Environment.TickCount read to compute elapsed-since-last-implicit, e.g. (Environment.TickCount - scanner.LastReceivedImplicitMessageTickCount) > 5000 for a 5-second watchdog. Unlike LastReceivedImplicitMessage, this value is not affected by NTP sync, DST changes, or manual clock adjustment.

IdentityObject

public ObjectLibrary.IdentityObject IdentityObject { get; }

Implementation of the identity Object (Class Code: 0x01) - Required Object according to CIP-Specification

MessageRouterObject

public ObjectLibrary.MessageRouterObject MessageRouterObject { get; }

Implementation of the Message Router Object (Class Code: 0x02) - Required Object according to CIP-Specification

AssemblyObject

public ObjectLibrary.AssemblyObject AssemblyObject { get; }

Implementation of the Assembly Object (Class Code: 0x04)

TcpIpInterfaceObject

public ObjectLibrary.TcpIpInterfaceObject TcpIpInterfaceObject { get; }

Implementation of the TCP/IP Object (Class Code: 0xF5) - Required Object according to CIP-Specification

Methods

ListIdentity(NetworkController networkController, TimeSpan timeout)

public Encapsulation.CIPIdentityItem[] ListIdentity(NetworkController networkController, TimeSpan timeout)

Broadcasts an EIP List Identity command and collects responses from every EtherNet/IP device on the local subnet during the timeout window.

ParameterTypeDescription
networkControllerNetworkControllerThe TinyCLR NetworkController whose IP/mask is used to compute the broadcast address.
timeoutTimeSpanHow long to listen for responses. Spec says devices reply within a random 0–2 s delay window, so use ≥ 2 s for reliable discovery. Pass TimeSpan.Zero to wait indefinitely (not recommended).

Returns Encapsulation.CIPIdentityItem[] — One Encapsulation.CIPIdentityItem per responding device, or null if no device responded.

RegisterSession(uint address, ushort port)

public uint RegisterSession(uint address, ushort port)

Opens a TCP connection to the target on port 44818 (0xAF12) and sends an EIP RegisterSession command to establish an encapsulation session. Required before any explicit-messaging service (GetAttributeSingle, ForwardOpen, etc.) can be sent.

ParameterTypeDescription
addressuintTarget IP as a packed 32-bit value: top byte is the first IPv4 octet (e.g. 192.168.1.1 = 0xC0A80101). Use the string overload if you have a dotted-quad string.
portushortTCP port — typically 0xAF12 (44818, EIP standard). Pass a non-standard port only if the target listens elsewhere.

Returns uint — The 32-bit session handle assigned by the target. Stored internally; you typically don't need to inspect it.

UnRegisterSession()

public void UnRegisterSession()

Sends an EIP UnregisterSession command to gracefully close the encapsulation session, then closes the TCP connection. Idempotent — safe to call even if the target has already dropped. Dispose calls this for you.

Dispose()

public void Dispose()

Tears down the scanner cleanly: closes the Class-1 connection (ForwardClose), unregisters the encapsulation session, closes all sockets. Each sub-step swallows its own exceptions so Dispose itself never throws (per the IDisposable contract). Idempotent and safe to call from a using block on any code path including before ForwardOpen().

ForwardOpen()

public void ForwardOpen()

Opens a Class-1 (implicit / cyclic I/O) connection to the target using regular Forward Open (service 0x54). Configure all connection-related properties (IPAddress, O_T_InstanceID, T_O_InstanceID, RequestedPacketRate_O_T, O_T_RealTimeFormat, etc.) before calling.

ForwardOpen(bool largeForwardOpen)

public void ForwardOpen(bool largeForwardOpen)

Opens a Class-1 implicit connection, choosing between regular Forward Open (service 0x54) and Large Forward Open (service 0x5B) based on the largeForwardOpen flag. Large form is required when either direction's payload exceeds ~500 bytes.

ParameterTypeDescription
largeForwardOpenbooltrue → use Large Forward Open (32-bit connection parameters, allows up to ~65 KB per direction); false → use regular Forward Open.

LargeForwardOpen()

public void LargeForwardOpen()

No description available.

Detect_O_T_Length()

public ushort Detect_O_T_Length ()

Detects the Length of the data Originator -> Target. The Method uses an Explicit Message to detect the length. The IP-Address, Port and the Instance ID has to be defined before

Returns ushort

Detect_T_O_Length()

public ushort Detect_T_O_Length()

Detects the Length of the data Target -> Originator. The Method uses an Explicit Message to detect the length. The IP-Address, Port and the Instance ID has to be defined before

Returns ushort

ForwardClose()

public void ForwardClose()

Sends a Forward Close to tear down the Class-1 implicit connection, stops the producer thread, waits for the producer to exit, then sends the close request and closes the UDP receive socket. Safe to call from a using block via Dispose.

RegisterSession(string address, ushort port)

public uint RegisterSession(string address, ushort port)

Sends a RegisterSession command to a target to initiate session

ParameterTypeDescription
addressstringIP-Address of the target device
portushortPort of the target device (default should be 0xAF12)

Returns uint — Session Handle

RegisterSession(string address)

public uint RegisterSession(string address)

Sends a RegisterSession command to a target to initiate session with the Standard or predefined Port (Standard: 0xAF12)

ParameterTypeDescription
addressstringIP-Address of the target device

Returns uint — Session Handle

RegisterSession()

public uint RegisterSession()

Sends a RegisterSession command to a target to initiate session with the Standard or predefined Port and Predefined IPAddress (Standard-Port: 0xAF12)

Returns uint — Session Handle

GetAttributeSingle(int classID, int instanceID, int attributeID)

public byte[] GetAttributeSingle(int classID, int instanceID, int attributeID)

Sends a CIP Get_Attribute_Single (service 0x0E) to read one attribute from the target. Auto-registers a session if not already open. Blocks until the target replies or the underlying TCP read times out.

ParameterTypeDescription
classIDintCIP class code (e.g. 0x01 = Identity).
instanceIDintInstance number, 1-based.
attributeIDintAttribute ID within the instance.

Returns byte[] — Raw attribute bytes. Endianness and structure depend on the attribute's CIP type — use the ToUshort/ToUint helpers or the strongly-typed accessors on ObjectLibrary.IdentityObject etc. for common cases.

GetAttributeAll(int classID, int instanceID)

public byte[] GetAttributeAll(int classID, int instanceID)

Implementation of Common Service "Get_Attribute_All" - Service Code: 0x01

ParameterTypeDescription
classIDintClass id of requested Attributes
instanceIDintInstance of Requested Attributes (0 for class Attributes)

Returns byte[] — Session Handle

SetAttributeSingle(int classID, int instanceID, int attributeID, byte[] value)

public byte[] SetAttributeSingle(int classID, int instanceID, int attributeID, byte[] value)

Sends a CIP Set_Attribute_Single (service 0x10) to write one attribute on the target. Auto-registers a session if not already open.

ParameterTypeDescription
classIDintCIP class code.
instanceIDintInstance number, 1-based.
attributeIDintAttribute ID within the instance.
valuebyte[]Raw bytes to write. Must match the attribute's CIP type width and endianness — most types are little-endian on the wire.

Returns byte[] — Any reply bytes the target included. Usually empty.

GetAttributeAll(int classID)

public byte[] GetAttributeAll(int classID)

Implementation of Common Service "Get_Attribute_All" - Service Code: 0x01

ParameterTypeDescription
classIDintClass id of requested Attributes

Returns byte[]

ToUshort(byte[] byteArray)

public static ushort ToUshort(byte[] byteArray)

Converts a bytearray (received e.g. via getAttributeSingle) to ushort

ParameterTypeDescription
byteArraybyte[]bytearray to convert

Returns ushort

ToUint(byte[] byteArray)

public static uint ToUint(byte[] byteArray)

Converts a bytearray (received e.g. via getAttributeSingle) to uint

ParameterTypeDescription
byteArraybyte[]bytearray to convert

Returns uint

ToBool(byte inputbyte, int bitposition)

public static bool ToBool(byte inputbyte, int bitposition)

Returns the "Bool" State of a byte Received via getAttributeSingle

ParameterTypeDescription
inputbytebytebyte to convert
bitpositionintbitposition to convert (First bit = bitposition 0)

Returns bool — Converted bool value

Events

ConnectionEstablished

public event EipEventHandler ConnectionEstablished

Fired once after a successful ForwardOpen / LargeForwardOpen.

ConnectionLost

public event EipEventHandler ConnectionLost

Fired when the implicit producer (sendUDP) repeatedly fails to send, or when the target stops producing for longer than the RPI watchdog. Not fired on a user-initiated ForwardClose / Dispose.

ImplicitDataReceived

public event ImplicitDataReceivedHandler ImplicitDataReceived

Fired on every Class-1 packet received from the target. The byte[] argument is a freshly-allocated snapshot of the payload — safe to retain, safe to read off-thread. T_O_IOData is also updated, but the snapshot is the race-free way to consume implicit input.

RpiViolated

public event EipEventHandler RpiViolated

Fired when an implicit packet arrives later than the negotiated RPI tolerance (currently fires when the inter-arrival gap exceeds 4 * RPI). Diagnostic only; the connection is not automatically closed.