using DataService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace OmronPlcDriver
{
[Description("Omron(CS/CJ) UDP协议")]
public sealed class OmronCsCjUDPReader : IPLCDriver, IMultiReadWrite //IPLCDriver : IDriver, IReaderWriter IDriver : IDisposable
{
#region
/****************************************/
//更新人: zjf
//更新内容:新增_pdu,可以根据实际情况进行采集
//更新日期:20171205
//更新原因:根据现场进行参数调整以提高采集响应速度或者减小网络压力
/***************************************/
///
/// PDU的值,包大小上限
///
int _pdu;
///
/// 获取PDU的值
///
public int PDU
{
get { return _pdu; }
set { _pdu = value; }
}
///
/// 获取设备地址
///
///
///
public DeviceAddress GetDeviceAddress(string address)
{
DeviceAddress dv = DeviceAddress.Empty;
if (string.IsNullOrEmpty(address))
return dv;
dv.Area = _plcNodeId;
switch (address[0])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctCIO;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(0, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address);
}
break;
case 'D'://DM区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctDM;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
}
break;
case 'H'://HR区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctHR;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
}
break;
case 'A'://AR区
{
int index = address.IndexOf('.');
dv.DBNumber = OmronCSCJ.fctA;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
}
break;
}
dv.ByteOrder = ByteOrder.Network;
return dv;
}
public string GetAddress(DeviceAddress address)
{
return string.Empty;
}
#endregion
private int _timeout;//超时数据
private Socket udpSynCl;
//接受字符串
private byte[] udpSynClBuffer = new byte[1024];
short _id;//驱动id
//驱动id
public short ID
{
get
{
return _id;
}
}
string _name;//驱动名称
///
/// 驱动名称
///
public string Name
{
get
{
return _name;
}
}
string _ip;//服务ip
int _port = 9600; //服务端口
public int Port
{
get { return _port; }
set { _port = value; }
}
public string ServerName
{
get { return _ip; }
set { _ip = value; }
}
///
/// 是否关闭
///
public bool IsClosed
{
get
{
return udpSynCl == null || udpSynCl.Connected == false;
}
}
///
/// 超时时间
///
public int TimeOut
{
get { return _timeout; }
set { _timeout = value; }
}
byte _plcNodeId;//plc节点号
///
/// plc节点号,从para1参数读取
///
public byte PlcNodeId
{
get { return _pcNodeId; }
set { _pcNodeId = value; }
}
byte _pcNodeId;//电脑节点号
///
/// 电脑节点号,从para2参数读取
///
public byte PcNodeId
{
get { return _pcNodeId; }
set { _pcNodeId = value; }
}
List _grps = new List(20);
public IEnumerable Groups
{
get { return _grps; }
}
IDataServer _server;
public IDataServer Parent
{
get { return _server; }
}
public OmronCsCjUDPReader(IDataServer server, short id, string name)
{
_id = id;
_name = name;
_server = server;
}
///
/// 连接
///
///
public bool Connect()
{
try
{
Console.WriteLine("开始连接");
if (udpSynCl != null)
udpSynCl.Close();
//IPAddress ip = IPAddress.Parse(_ip);
// ----------------------------------------------------------------
// Connect synchronous client
udpSynCl = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udpSynCl.SendTimeout = _timeout;
udpSynCl.ReceiveTimeout = _timeout;
udpSynCl.Connect(_ip, _port);
return true;
}
catch (SocketException error)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(error.Message));
return false;
}
}
///
/// 生成读命令头
///
/// 电脑节点号,设置和PLC节点不一致即可
/// 读取的起始地址
/// 读取长度,2个字节为一个单位
///
/// PLC节点号,可为0
///
private byte[] CreateReadHeader(byte pcnode, int startAddress, ushort length, byte function, byte plcnode = 0)
{
//80 00 00 14 00 00 00 FD 00 00 01 01 00 00 00 00 00 01
//80 00 02 00 41 00 00 0B 00 00 01 01 82 00 64 00 00 14
byte[] data = new byte[18];
data[0] = 0x80;
data[1] = 0;
data[2] = 0; //80 00 02 固定帧头
data[2] = 0;
data[3] = plcnode;
data[5] = 0; //设备的网络号,节点号,单元号
data[6] = 0;
data[7] = pcnode;
data[8] = 0; //PC的网络号,节点号,单元号
data[9] = 0;
data[10] = 1;
data[11] = 1; //SID+MRC+SRC
data[12] = function; //数据区代码
byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress));
data[13] = _adr[0]; // 首地址高字节
data[14] = _adr[1]; // 首地址低字节
data[15] = 0; // 固定0
byte[] _length = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)length));
data[16] = _length[0]; // 读取数量高字节
data[17] = _length[1]; // 读取数量低字节
return data;
}
///
/// 生成写命令头
///
///
///
///
///
///
///
private byte[] CreateWriteHeader(byte pcnode, int startAddress, ushort numData, byte function, byte plcnode = 0)
{
byte[] data = new byte[numData + 18];
data[0] = 0x80;
data[1] = 0;
data[2] = 0; //80 00 02 固定帧头
data[3] = 0;
data[4] = plcnode;
data[5] = 0; //设备的网络号,节点号,单元号
data[6] = 0;
data[7] = pcnode;
data[8] = 0; //PC的网络号,节点号,单元号
data[9] = 0;
data[10] = 1;
data[11] = 2; //SID+MRC+SRC
data[12] = function; //数据区代码
byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress));
data[13] = _adr[0]; // 首地址高字节
data[14] = _adr[1]; // 首地址低字节
data[15] = 0; // 固定0
byte[] length = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)numData / 2));
data[16] = length[0]; // 写取数量高字节
data[17] = length[1]; // 写取数量低字节
return data;
}
///
/// 同步写数据到udp
///
/// 写的字节数组
///
private byte[] WriteSyncData(byte[] write_data)
{
short id = BitConverter.ToInt16(write_data, 4);
if (IsClosed) CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
else
{
try
{
udpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);//是否存在lock的问题?
int result = udpSynCl.Receive(udpSynClBuffer, 0, 1024, SocketFlags.None);
byte function = udpSynClBuffer[11];//读写功能
byte[] data;
int err = udpSynClBuffer[12] * 256 + udpSynClBuffer[13];
if (result == 0) CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
// ------------------------------------------------------------
// Response data is slave ModbusModbus.exception
if (err != 0)
{
CallException(id, function, 4);
return null;
}
// ------------------------------------------------------------
// Write response data
else if (function == 0x2)
{
data = new byte[2];
Array.Copy(udpSynClBuffer, 10, data, 0, 2);
}
// ------------------------------------------------------------
// Read response data
else if (function == 0x1)
{
data = new byte[(write_data[16] * 256 + write_data[17]) * 2];
Array.Copy(udpSynClBuffer, 14, data, 0, data.Length);
}
else
{
return null;
}
return data;
}
catch (SocketException)
{
CallException(id, write_data[12], OmronCSCJ.excExceptionConnectionLost);
}
}
return null;
}
///
/// 写单个寄存器
///
/// 电脑节点号
/// 起始地址
/// 内存区功能吗
/// 写值数组
/// plc节点号
///
public byte[] WriteSingleRegister(byte pcnode, int startAddress, byte function, byte[] values, byte plcnode = 0)
{
byte[] data;
data = CreateWriteHeader(pcnode, startAddress, 2, function, plcnode);
data[19] = values[0];
data[20] = values[1];
return WriteSyncData(data);
}
///
/// 写多个寄存器
///
/// 电脑节点号
/// 起始地址
/// 内存区功能号
/// 写值数组
/// plc节点号
///
public byte[] WriteMultipleRegister(byte pcnode, int startAddress, byte function, byte[] values, byte plcnode = 0)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateWriteHeader(pcnode, startAddress, numBytes, function, plcnode);
Array.Copy(values, 0, data, 19, values.Length);
return WriteSyncData(data);
}
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
NetShortGroup grp = new NetShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
public bool RemoveGroup(IGroup grp)
{
grp.IsActive = false;
return _grps.Remove(grp);
}
public void Dispose()
{
if (udpSynCl != null)
{
try { udpSynCl.Shutdown(SocketShutdown.Both); }
catch { }
udpSynCl.Close();
udpSynCl = null;
}
foreach (IGroup grp in _grps)
{
grp.Dispose();
}
_grps.Clear();
}
internal string GetErrorString(byte exception)
{
switch (exception)
{
case OmronCSCJ.excIllegalFunction:
return "Constant for OmronCSCJ.exception illegal function.";
case OmronCSCJ.excIllegalDataAdr:
return "Constant for OmronCSCJ.exception illegal data address.";
case OmronCSCJ.excIllegalDataVal:
return "Constant for OmronCSCJ.exception illegal data value.";
case OmronCSCJ.excSlaveDeviceFailure:
return "Constant for OmronCSCJ.exception slave device failure.";
case OmronCSCJ.excAck:
return "Constant for OmronCSCJ.exception acknowledge.";
case OmronCSCJ.excSlaveIsBusy:
return "Constant for OmronCSCJ.exception slave is busy/booting up.";
case OmronCSCJ.excGatePathUnavailable:
return "Constant for OmronCSCJ.exception gate path unavailable.";
case OmronCSCJ.excExceptionNotConnected:
return "Constant for OmronCSCJ.exception not connected.";
case OmronCSCJ.excExceptionConnectionLost:
return "Constant for OmronCSCJ.exception connection lost.";
case OmronCSCJ.excExceptionTimeout:
return "Constant for OmronCSCJ.exception response timeout.";
case OmronCSCJ.excExceptionOffset:
return "Constant for OmronCSCJ.exception wrong offset.";
case OmronCSCJ.excSendFailt:
return "Constant for OmronCSCJ.exception send failt.";
}
return string.Empty;
}
internal void CallException(int id, byte function, byte exception)
{
if (udpSynCl == null) return;
//Console.WriteLine("OmronReader错误->" + GetErrorString(exception));
if (exception == OmronCSCJ.excExceptionConnectionLost && IsClosed == false)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception)));
}
}
///
/// 读取字节数组
///
/// 标签变量地址结构
/// 长度,
///
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
ushort len = size;
if (len % 2 != 0)
{
len++;
}
return WriteSyncData(CreateReadHeader(PcNodeId, address.Start, (ushort)(len), (byte)address.DBNumber, (byte)address.Area));
}
///
/// 读取32位整数
///
/// 标签变量地址结构
///
public ItemData ReadInt32(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 2, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData(IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData ReadUInt32(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 2, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData((uint)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData ReadUInt16(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData((ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt16(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
///
/// 读取16位整数
///
/// 标签变量地址结构
///
public ItemData ReadInt16(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData(IPAddress.HostToNetworkOrder(BitConverter.ToInt16(data, 0)), 0, QUALITIES.QUALITY_GOOD);
}
///
/// 读取1字节
///
/// 标签变量地址结构
///
public ItemData ReadByte(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData(data[0], 0, QUALITIES.QUALITY_GOOD);
}
///
/// 读取字符串
///
/// 标签变量地址结构
/// 长度
///
public ItemData ReadString(DeviceAddress address, ushort size)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, size, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(string.Empty, 0, QUALITIES.QUALITY_BAD);
else
return new ItemData(Encoding.ASCII.GetString(data, 0, data.Length), 0, QUALITIES.QUALITY_GOOD);//是否考虑字节序问题?
}
///
/// 读取32位浮点数
///
/// 标签变量地址结构
///
public unsafe ItemData ReadFloat(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 2, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(0.0f, 0, QUALITIES.QUALITY_BAD);
else
{
int value = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0));
return new ItemData(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD);
}
}
///
/// 读取1位
///
/// 标签变量地址结构体
///
public ItemData ReadBit(DeviceAddress address)
{
byte[] data = WriteSyncData(CreateReadHeader(PcNodeId, address.Start, 1, (byte)address.DBNumber, (byte)address.Area));
if (data == null)
return new ItemData(false, 0, QUALITIES.QUALITY_BAD);
if (data.Length == 1) return new ItemData(data[0] > 0, 0, QUALITIES.QUALITY_GOOD);
unsafe
{
fixed (byte* p = data)
{
short* p1 = (short*)p;
return new ItemData((*p1 & (1 << address.Bit.BitSwap()))
!= 0, 0, QUALITIES.QUALITY_GOOD);
}
}
}
///
/// 读object类型
///
///
///
public ItemData