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
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 the Compolet
- Read variables (ReadVariable)
- Write variables (WriteVariable)
- Read/write structures
- Write the clock (Clock)
- Other 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
The alignment is as shown below
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
| Name | Description | |
|---|---|---|
| Properties | ReceiveTimeLimit | Gets or sets the time until the Compolet's receive wait times out |
| IsConnected | Gets whether it is connected to the node | |
| TypeName | Gets the PLC model information | |
| RunStatus | Represents the operating status of the PLC | |
| Methods | ReadVariableMultiple | Reads the values of multiple PLC tags |
| GetEventLogs | Gets the PLC event log |
See the help file for all members
The help file is in [Start] - [OMRON] - [CX-Compolet]
