日本語 English

CIP communication sample

Overview

This article explains CIP communication (EtherNet/IP) with OMRON NJ/NX series PLCs.
It shows how to read and write PLC variables from C# using NJCompolet, how to handle structures and how to set the PLC clock.

What Is CIP Communication?

CIP (Common Industrial Protocol) is the industrial communication protocol used by EtherNet/IP.
With OMRON NJ/NX series PLCs, Windows applications can access PLC variables using NJCompolet.

NJCompolet component

Place NJCompolet on the form with the instance name njCompolet1
NJCompolet icon

The sample code below is written in C#
Creating the form (placing buttons, etc.) is omitted, so place buttons and so on as needed

Main members

Activate njCompolet1

To communicate, set the IP address of the target PLC and set the Active property to True
In the sample, these are set when the form loads

private void Form1_Load(object sender, EventArgs e)
{
	njCompolet1.PeerAddress = "192.168.250.1";		//PLC IP address
	njCompolet1.Active = true;
}

Explanation: PeerAddress, Active

Lines 3-4


njCompolet1.PeerAddress = "192.168.250.1";		//PLC IP address
njCompolet1.Active = true;
	

Set the IP address of the destination PLC in PeerAddress and set Active to True
Setting Active to True opens a connection with the PLC at PeerAddress

Reading Variables

Clicking button1 executes the ReadVariable method and reads the variable values

private void button1_Click(object sender, EventArgs e)
{
	try
	{
		// Numeric and real types
		Int32 vInt = (Int32)njCompolet1.ReadVariable("variableInt");
		float vReal = (float)njCompolet1.ReadVariable("variableReal");

		// Date and time
		DateTime vDate = (DateTime)njCompolet1.ReadVariable("variableDate");
		TimeSpan vTime = (TimeSpan)njCompolet1.ReadVariable("variableTime");
		DateTime vDateTime = (DateTime)njCompolet1.ReadVariable("variableDateAndTime");

		// String
		string vStr = (string)njCompolet1.ReadVariable("variableString");

		// Array
		int[] vAryInt = (int[])njCompolet1.ReadVariable("variableAryInt");

	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
}
	

Explanation: ReadVariable

Line 6


Int32 vInt = (Int32)njCompolet1.ReadVariable("variableInt");
	

The ReadVariable method reads the PLC variable variableInt and stores it in the variable vInt
The return value of ReadVariable is of type Object, so it is cast to int
variableInt on the PLC is a global variable with Network Publish set to "Publish Only", "Input" or "Output"

Lines 7-18


float vReal = (float)njCompolet1.ReadVariable("variableReal");

// Date and time
DateTime vDate = (DateTime)njCompolet1.ReadVariable("variableDate");
TimeSpan vTime = (TimeSpan)njCompolet1.ReadVariable("variableTime");
DateTime vDateTime = (DateTime)njCompolet1.ReadVariable("variableDateAndTime");

// String
string vStr = (string)njCompolet1.ReadVariable("variableString");

// Array
int[] vAryInt = (int[])njCompolet1.ReadVariable("variableAryInt");
	

Likewise, Real, Date, Time, DateTime and String types are read
Arrays can also be read by casting to an array

Writing Variables

private void button2_Click(object sender, EventArgs e)
{
	try
	{
		// Numeric and real types
		njCompolet1.WriteVariable("variableInt", 1);
		njCompolet1.WriteVariable("variableReal", 1.23);

		// Date and time
		njCompolet1.WriteVariable("variableDate", DateTime.Now);
		njCompolet1.WriteVariable("variableTime", new TimeSpan(1, 0, 0));
		njCompolet1.WriteVariable("variableDateAndTime", DateTime.Now);

		// String
		njCompolet1.WriteVariable("variableString", "ABC");

		// Array
		int[] intValue = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		njCompolet1.WriteVariable("variableAryInt", intValue);

	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
}
	

Explanation: WriteVariable

Line 6


njCompolet1.WriteVariable("variableInt", 1);
	

The WriteVariable method writes the number 1 to the PLC variable variableInt

Lines 7-19


njCompolet1.WriteVariable("variableReal", 1.23);

// Date and time
njCompolet1.WriteVariable("variableDate", DateTime.Now);
njCompolet1.WriteVariable("variableTime", new TimeSpan(1, 0, 0));
njCompolet1.WriteVariable("variableDateAndTime", DateTime.Now);

// String
njCompolet1.WriteVariable("variableString", "ABC");

// Array
int[] intValue = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
njCompolet1.WriteVariable("variableAryInt", intValue);
	

Likewise, Real, Date, Time, DateTime and String types are written
Arrays can be written in the same way

Reading and Writing Structures

Reading

When a structure is read with ReadVariable, the data is returned as a byte array
If the structure members have different data types (sizes), be careful about alignment


For the following structure
Example structure


The alignment is as shown below
Structure alignment


Convert the read byte array to each data type in order from the start using BitConverter
For String, search for the null character and convert that many bytes from the byte array to a String variable

private void button3_Click(object sender, EventArgs e)
{
	Encoding enc = Encoding.GetEncoding("utf-8");
	byte[] byteArray = new byte[256];
	int pos = 0;

	try
	{
		byte[] bytesTestStruct = (byte[])njCompolet1.ReadVariable("TestStruct");

		UInt16 variableBool = BitConverter.ToUInt16(bytesTestStruct, 0);
		Int16 variableInt = BitConverter.ToInt16(bytesTestStruct, 2);
		UInt16 variableUInt = BitConverter.ToUInt16(bytesTestStruct, 4);
		Int32 variableDint = BitConverter.ToInt32(bytesTestStruct, 8);

		Array.Copy(bytesTestStruct, 12, byteArray, 0, 256);
		pos = Array.IndexOf(byteArray, (byte)0);		//search for null to get the number of bytes
		if (pos == -1) pos = 256;			//maximum if no null is found
		string variableStr = enc.GetString(byteArray, 0, pos);
		Console.WriteLine(variableStr);
	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
}
	

Explanation

Line 3


Encoding enc = Encoding.GetEncoding("utf-8");
	

The PLC string encoding is UTF-8, so prepare a UTF-8 encoding

Line 4


byte[] byteArray = new byte[256];
	

Prepare a byte array to hold the string

Line 9


byte[] bytesTestStruct = (byte[])njCompolet1.ReadVariable("TestStruct");
	

Read the structure with ReadVariable and store it in the byte array bytesTestStruct

Lines 11-14


UInt16 variableBool = BitConverter.ToUInt16(bytesTestStruct, 0);
Int16 variableInt = BitConverter.ToInt16(bytesTestStruct, 2);
UInt16 variableUInt = BitConverter.ToUInt16(bytesTestStruct, 4);
Int32 variableDint = BitConverter.ToInt32(bytesTestStruct, 8);
	

Use BitConverter to convert the value at the specified position in the byte array to a number
First, the 10 BOOLs at the start occupy 2 bytes, so they are read as UInt16 (BitConverter does not support BOOL)
Lines 12, 13 and 14 read the INT, UINT and DINT from bytes 2, 4 and 8 respectively

Lines 16-19


Array.Copy(bytesTestStruct, 12, byteArray, 0, 256);
pos = Array.IndexOf(byteArray, (byte)0);		//search for null to get the number of bytes
if (pos == -1) pos = 256;			//maximum if no null is found
string variableStr = enc.GetString(byteArray, 0, pos);
	

Lines 16 to 19 read the string starting at byte 12 of the byte array
Line 16 extracts 256 bytes from byte 12 into byteArray
Line 17 uses IndexOf to search for (byte)0 to find the null terminator of the string
Line 18 treats all 256 bytes as characters if no null is found
Line 19 encodes the byte array into a string and stores it in variableString

Writing

Set the data to write in a byte array and write it to the PLC
As when reading, pay attention to alignment when writing

private void button4_Click(object sender, EventArgs e)
{
	Encoding enc = Encoding.GetEncoding("utf-8");
	byte[] bytedata = new byte[1000];
	byte[] writedata = new byte[268];		//number of bytes in the structure

	UInt16 variableBool = 0x10;
	Int16 variableInt = -10;
	UInt16 variableUInt = 20;
	Int32 variableDint = 100000;

	try
	{
		Array.Copy(BitConverter.GetBytes(variableBool), 0, bytedata, 0, 2);
		Array.Copy(BitConverter.GetBytes(variableInt), 0, bytedata, 2, 2);
		Array.Copy(BitConverter.GetBytes(variableUInt), 0, bytedata, 4, 2);
		Array.Copy(BitConverter.GetBytes(variableDint), 0, bytedata, 8, 4);
		byte[] byteArray = enc.GetBytes("ABC");
		Array.Copy(byteArray, 0, bytedata, 12, 3);

		Array.Copy(bytedata, writedata, 16);
		njCompolet1.WriteVariable("TestStruct", writedata);
	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
}
	

Explanation

Line 3


Encoding enc = Encoding.GetEncoding("utf-8");
	

The PLC string encoding is UTF-8, so prepare a UTF-8 encoding

Lines 4-5


byte[] bytedata = new byte[1000];
byte[] writedata = new byte[268];		//number of bytes in the structure
	

bytedata on line 4 is a working byte array of 1000 bytes
writedata on line 5 is the byte array for writing to the structure, sized to the structure's 268 bytes

Lines 7-10


UInt16 variableBool = 0x10;
Int16 variableInt = -10;
UInt16 variableUInt = 20;
Int32 variableDint = 100000;
	

Prepare the data to write to each variable

Lines 14-19


Array.Copy(BitConverter.GetBytes(variableBool), 0, bytedata, 0, 2);
Array.Copy(BitConverter.GetBytes(variableInt), 0, bytedata, 2, 2);
Array.Copy(BitConverter.GetBytes(variableUInt), 0, bytedata, 4, 2);
Array.Copy(BitConverter.GetBytes(variableDint), 0, bytedata, 8, 4);
byte[] byteArray = enc.GetBytes("ABC");
Array.Copy(byteArray, 0, bytedata, 12, 3);
	

Convert numbers to byte arrays with BitConverter.GetBytes and store them in bytedata
Line 18 is a string, so it is encoded into a byte array with GetBytes and then copied into bytedata on line 19

Lines 21-22


Array.Copy(bytedata, writedata, 16);
njCompolet1.WriteVariable("TestStruct", writedata);
	

Line 21 copies from the working bytedata to writedata for writing
Line 22 writes the values of writedata to the PLC structure TestStruct with WriteVariable

Note when a member is of type DATE_AND_TIME

NJ/NX time counts in 1 ns units from 1970-01-01
Windows time counts in 100 ns units from 0001/01/01 00:00:00.000
If a structure member is a date/time, the byte array contains the elapsed time (count) above, so convert the read value to a Windows date/time as elapsed time from 1970-01-01

double msec =(double)(BitConverter.ToUInt64(bytesTestStruct, 0)) / 1000000.0;
DateTime variableDateTime = new DateTime(1970, 1, 1).AddMilliseconds(msec);
	

This is also explained in detail in the sample How to Convert PLC Unix Time to Windows Time

Writing the Clock

Clicking button5 writes the PC time to the PLC

private void button5_Click(object sender, EventArgs e)
{
	try
	{
		njCompolet1.Clock = DateTime.Now;
	}
	catch(Exception ex)
	{
		Console.WriteLine(ex.Message);
	}
}
	

Explanation: Clock

Line 5


njCompolet1.Clock = DateTime.Now;
	

Writing the PC time directly to the Clock property changes the PLC time

Other Frequently Used Members

Member
NameDescription
PropertiesReceiveTimeLimitGets or sets the time until the Compolet's receive wait times out
IsConnectedGets whether it is connected to the node
TypeNameGets the PLC model information
RunStatusRepresents the operating status of the PLC
MethodsReadVariableMultipleReads the values of multiple PLC tags
GetEventLogsGets the PLC event log

See the help file for all members
The help file is in [Start] - [OMRON] - [CX-Compolet]

Comments