using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 欧姆龙EIP调试.EIP
{
///
/// CIP通信工具类
///
public class CIPHelper
{
///
/// IP地址
///
public string IpAddress { get; set; }
///
/// 通信端口号
///
public int Port { get; set; }
public bool IsConnected
{
get
{
if (client == null)
return false;
return client.Connected;
}
}
private Socket client;
public int SessionHandle = 0;
///
/// 默认无参构造
///
public CIPHelper()
{
}
///
/// 构造方法,传递通信IP与端口
///
public CIPHelper(string ip, int port)
{
this.IpAddress = ip;
this.Port = port;
}
///
/// 建立连接
///
public void Connect()
{
//连接
try
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(new IPEndPoint(IPAddress.Parse(IpAddress), Port));
}
catch (Exception ex)
{
}
}
///
/// 注册会话
///
public bool RegisterSession()
{
//注册会话
if (client != null && client.Connected)
{
byte[] registerSessionBytes = { (byte)0x65, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
client.Send(registerSessionBytes);
Thread.Sleep(20);
byte[] rev = new byte[1024];
try
{
int length = client.Receive(rev);
byte[] data = new byte[length];
Array.Copy(rev, 0, data, 0, length);
if (data[0] == 0x65)
return GetSessionHandle(data);
}
catch
{
return false;
}
}
return false;
}
///
/// 读取标签值
///
///
///
public object ReadTag(string tag)
{
if (client == null)
return null;
if (!client.Connected)
return null;
if (SessionHandle == 0)
return null;
byte[] d = GetReadTagBytes(tag);
client.Send(d);
Thread.Sleep(20);
byte[] rev = new byte[1024];
try
{
int length = client.Receive(rev);
byte[] data = new byte[length];
Array.Copy(rev, 0, data, 0, length);
if (data[0] == 0x6f)
return ReadTagVal(data);
return null;
}
catch
{
return null;
}
}
public bool WriteTag(string tag, object value)
{
if (client == null)
return false;
if (!client.Connected)
return false;
if (SessionHandle == 0)
return false;
byte[] d = GetWriteTagBytes(tag, value);
client.Send(d);
Thread.Sleep(20);
byte[] rev = new byte[1024];
try
{
int length = client.Receive(rev);
byte[] data = new byte[length];
Array.Copy(rev, 0, data, 0, length);
if (data[0] == 0x6f)
return WriteTagVal(data);
return false;
}
catch
{
return false;
}
}
///
/// 注销会话
///
///
public bool UnRegisterSession()
{
if (client == null)
return false;
if (!client.Connected)
return false;
if (SessionHandle == 0)
return false;
List UnregisterSession = new List();
UnregisterSession.AddRange(new List { (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x00 });
UnregisterSession.AddRange(BitConverter.GetBytes(SessionHandle));
UnregisterSession.AddRange(new List { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 });
try
{
client.Send(UnregisterSession.ToArray());
return true;
}
catch
{
return false;
}
}
///
/// 断开连接
///
public void DisConnect()
{
if (client == null)
return;
//断开
try
{
if (IsConnected)
{
client.Close();
}
client = null;
SessionHandle = 0;
}
catch (Exception ex)
{
client = null;
SessionHandle = 0;
}
}
#region Private
///
/// 解析写标签数据
///
///
///
private bool WriteTagVal(byte[] data)
{
int byte_index = 0;
short var1 = BitConverter.ToInt16(data, 0);//命令码
short var2 = BitConverter.ToInt16(data, 2);//去除Hearder后的长度
if ((var2 + 24) != data.Length)//24是Hearder封装头的长度 封装头长度+后面报文长度 应该等于总长度 否则报文错误
{
return false;
}
int sessionHandle = BitConverter.ToInt32(data, 4);
if (sessionHandle != this.SessionHandle)
{
//如果会话句柄不一致 返回
return false;
}
int state = BitConverter.ToInt32(data, 8);
if (state != 0)
{
//会话状态不正确
return false;
}
//00 00 00 00 01 00 02 00 00 00 00 00 B2 00 08 00 CC 00 00 00 C1 00 00 00
//发送方描述
byte_index = 12; //8
//选项 4字节
byte_index = 20;
//接口句柄 4字节
byte_index = 24;
//超时 2字节
byte_index = 28;
//项数 2字节
byte_index = 30;
//连接的地址项 2字节
byte_index = 32;
//连接地址项长度 2字节
byte_index = 34;
//未连接数据项 2字节
byte_index = 36;
//连接长度 2字节
byte_index = 38;
//数据开始
byte_index = 40;
for (int i = byte_index; i < data.Length; i++)
{
if (data[i] != 0xCD)
continue;
//填充字节 1字节
if (BitConverter.ToInt16(data, i + 2) != 0x00)
{
return true;
}
return false;
}
return false;
}
///
/// 解析读标签数据
///
///
///
private object ReadTagVal(byte[] data)
{
int byte_index = 0;
short var1 = BitConverter.ToInt16(data, 0);//命令码
short var2 = BitConverter.ToInt16(data, 2);//去除Hearder后的长度
if ((var2 + 24) != data.Length)//24是Hearder封装头的长度 封装头长度+后面报文长度 应该等于总长度 否则报文错误
{
return null;
}
int sessionHandle = BitConverter.ToInt32(data, 4);
if (sessionHandle != this.SessionHandle)
{
//如果会话句柄不一致 返回
return null;
}
int state = BitConverter.ToInt32(data, 8);
if (state != 0)
{
//会话状态不正确
return null;
}
//发送方描述
byte_index = 12; //8
//选项 4字节
byte_index = 20;
//接口句柄 4字节
byte_index = 24;
//超时 2字节
byte_index = 28;
//项数 2字节
byte_index = 30;
//连接的地址项 2字节
byte_index = 32;
//连接地址项长度 2字节
byte_index = 34;
//未连接数据项 2字节
byte_index = 36;
//连接长度 2字节
byte_index = 38;
//数据开始
byte_index = 40;
for (int i = byte_index; i < data.Length; i++)
{
if (data[i] != 0xCC)
continue;
//服务标识 0xCC
//填充字节 1字节
if (BitConverter.ToInt16(data, i + 2) != 0x00) // data[var4] != 0x00 || data[var4 + 1] != 0x00)
{
return null;
}
//数据类型
short dataType = BitConverter.ToInt16(data, i + 4);
if (dataType == 0x00C1)//BOOL
{
bool value = Convert.ToBoolean(((short)data[i + 6] & 0x00ff) | ((short)data[i + 7] << 8));
return value;
}
if (dataType == 0x00D1)//byte
{
byte value = data[i + 6];
return value;
}
if (dataType == 0x00C3)//int
{
short value = BitConverter.ToInt16(data, i + 6);// ((short)data[i+6] & 0x00ff) | ((short)data[i+7] << 8);
return value;
}
if (dataType == 0x00C4)//long型
{
int value = BitConverter.ToInt32(data, i + 6);
return value;
}
if (dataType == 0x00CA)//float
{
float value = BitConverter.ToSingle(data, i + 6);
return value;
}
}
return null;
}
///
/// 写标签报文数据
///
///
///
///
private byte[] GetWriteTagBytes(string tag, object value)
{
byte[] TagStringToAscii;
byte[] Var4 = Encoding.Default.GetBytes(tag);
if (Var4.Length % 2 == 0)
{
TagStringToAscii = new byte[Var4.Length];
for (int i = 0; i < Var4.Length; i++)
{
TagStringToAscii[i] = Var4[i];
}
}
else
{
TagStringToAscii = new byte[Var4.Length + 1];
for (int i = 0; i < Var4.Length; i++)
{
TagStringToAscii[i] = Var4[i];
}
TagStringToAscii[Var4.Length] = 0x00;
}
//CIP协议数据 =================================================
List Cip_Msg = new List();
Cip_Msg.Add((byte)0x4D);//服务标识
Cip_Msg.Add((byte)((TagStringToAscii.Length + 2) / 2));//CIP长度多少字 从标识开始 大读取标签长度结束
Cip_Msg.Add((byte)0x91);//固定
Cip_Msg.Add((byte)TagStringToAscii.Length);//PLC标签长度 多少个字节
Cip_Msg.AddRange(TagStringToAscii);//添加标签
//根据类型
if (value is bool)
{
Cip_Msg.AddRange(new byte[] { 0xC1, 0x00 });
if ((bool)value)
{
Cip_Msg.AddRange(new byte[] { 0x01, 0x00 });
}
else
{
Cip_Msg.AddRange(new byte[] { 0x00, 0x00 });
}
}
else if (value is byte)
{
Cip_Msg.AddRange(new byte[] { 0xD1, 0x00 });
Cip_Msg.Add((byte)value);
}
else if (value is short)
{
Cip_Msg.AddRange(new byte[] { 0xC3, 0x00 });
Cip_Msg.AddRange(BitConverter.GetBytes((short)value));
}
else if (value is int)
{
Cip_Msg.AddRange(new byte[] { 0xC4, 0x00 });
Cip_Msg.AddRange(BitConverter.GetBytes((int)value));
}
else if (value is float)
{
Cip_Msg.AddRange(new byte[] { 0xCA, 0x00 });
Cip_Msg.AddRange(BitConverter.GetBytes((float)value));
}
List Slot = new List { (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00 }; //槽号
List Cip_Msg0 = new List();
Cip_Msg0.Add((byte)0x52);//命令
Cip_Msg0.Add((byte)0X02);//请求路径长度
Cip_Msg0.AddRange(new byte[] { 0x20, 0x06, 0x24, 0x01 });//默认请求路径
Cip_Msg0.AddRange(new byte[] { 0x0A, 0xF0 });//默认超时
Cip_Msg0.AddRange(BitConverter.GetBytes((short)Cip_Msg.Count)); //后面报文长度 不包含PLC槽号
Cip_Msg0.AddRange(Cip_Msg);//添加CIP报文
List C_S_D = new List();
C_S_D.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//接口句柄 CIP
C_S_D.AddRange(new byte[] { 0x01, 0x00 });//超时时间 默认
C_S_D.AddRange(new byte[] { 0x02, 0x00 });//项数 默认
C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址项 默认
C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址长度 默认
C_S_D.AddRange(new byte[] { 0xB2, 0x00 });//未连接项 默认
C_S_D.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + Slot.Count)));//CIP报文包的长度 包括槽号
List Header = new List();
Header.AddRange(new byte[] { 0x6F, 0x00 });//命令码
Header.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + C_S_D.Count + Slot.Count)));//后面报文的长度 特定命令数据 和 CIP报文长度 和PLC槽号
Header.AddRange(BitConverter.GetBytes(SessionHandle));//添加会话句柄
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//添加状态
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //发送方描述
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//选项默认
List EtherNet_IP_CIP_MSG = new List();//单标签读取完整报文
EtherNet_IP_CIP_MSG.AddRange(Header);//添加Header 封装头
EtherNet_IP_CIP_MSG.AddRange(C_S_D);//添加特定命令数据
EtherNet_IP_CIP_MSG.AddRange(Cip_Msg0);//添加CIP报文
EtherNet_IP_CIP_MSG.AddRange(Slot);//添加槽号
return EtherNet_IP_CIP_MSG.ToArray();
}
///
/// 读标签报文数据
///
///
///
private byte[] GetReadTagBytes(string tag)
{
byte[] TagStringToAscii;
byte[] Var4 = Encoding.Default.GetBytes(tag);
if (Var4.Length % 2 == 0)
{
TagStringToAscii = new byte[Var4.Length];
for (int i = 0; i < Var4.Length; i++)
{
TagStringToAscii[i] = Var4[i];
}
}
else
{
TagStringToAscii = new byte[Var4.Length + 1];
for (int i = 0; i < Var4.Length; i++)
{
TagStringToAscii[i] = Var4[i];
}
TagStringToAscii[Var4.Length] = 0x00;
}
//CIP协议数据 =================================================
List Cip_Msg = new List();
Cip_Msg.Add((byte)0x4C);//服务标识
Cip_Msg.Add((byte)((TagStringToAscii.Length + 2) / 2));//CIP长度多少字 从标识开始 大读取标签长度结束
Cip_Msg.Add((byte)0x91);//固定
Cip_Msg.Add((byte)TagStringToAscii.Length);//PLC标签长度 多少个字节
Cip_Msg.AddRange(TagStringToAscii);//添加标签
Cip_Msg.Add((byte)0x01);
Cip_Msg.Add((byte)0x00); // 读取长度
List Slot = new List { (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00 }; //槽号
List Cip_Msg0 = new List();
Cip_Msg0.Add((byte)0x52);//命令
Cip_Msg0.Add((byte)0X02);//请求路径长度
Cip_Msg0.AddRange(new byte[] { 0x20, 0x06, 0x24, 0x01 });//默认请求路径
Cip_Msg0.AddRange(new byte[] { 0x0A, 0xF0 });//默认超时
Cip_Msg0.AddRange(BitConverter.GetBytes((short)Cip_Msg.Count)); //后面报文长度 不包含PLC槽号
Cip_Msg0.AddRange(Cip_Msg);//添加CIP报文
List C_S_D = new List();
C_S_D.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//接口句柄 CIP
C_S_D.AddRange(new byte[] { 0x01, 0x00 });//超时时间 默认
C_S_D.AddRange(new byte[] { 0x02, 0x00 });//项数 默认
C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址项 默认
C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址长度 默认
C_S_D.AddRange(new byte[] { 0xB2, 0x00 });//未连接项 默认
C_S_D.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + Slot.Count)));//CIP报文包的长度 包括槽号
List Header = new List();
Header.Add((byte)0x6F); Header.Add((byte)0x00);//命令码
Header.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + C_S_D.Count + Slot.Count)));//后面报文的长度 特定命令数据 和 CIP报文长度 和PLC槽号
Header.AddRange(BitConverter.GetBytes(SessionHandle));//添加会话句柄
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//添加状态
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //发送方描述
Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//选项默认
List EtherNet_IP_CIP_MSG = new List();//单标签读取完整报文
EtherNet_IP_CIP_MSG.AddRange(Header);//添加Header 封装头
EtherNet_IP_CIP_MSG.AddRange(C_S_D);//添加特定命令数据
EtherNet_IP_CIP_MSG.AddRange(Cip_Msg0);//添加CIP报文
EtherNet_IP_CIP_MSG.AddRange(Slot);//添加槽号
return EtherNet_IP_CIP_MSG.ToArray();
}
///
/// 注册会话结果解析
///
///
///
private bool GetSessionHandle(byte[] data)
{
//short sessionLength = BitConverter.ToInt16(data, 2);// (Convert.ToInt16(data[3]) * 256) | Convert.ToInt16(data[2]);
//byte[] var1 = new byte[4];
//for (int i = 0; i < 4; i++)
//{
// var1[i] = data[sessionLength + 4 + i];
//}
int state = BitConverter.ToInt32(data, 8);
if (state == 0)//判断报文状态
{
SessionHandle = BitConverter.ToInt32(data, 4);
//SessionHandle = new byte[sessionLength];
//for (int i = 0; i < sessionLength; i++)
//{
// SessionHandle[i] = data[4 + i];
//}
return true;
}
else
{
return false;
}
}
#endregion
}
}