using System;
using System.Net.Sockets;
using System.Threading;
namespace OmronFinsTCP.Net
{
public class EtherNetPLC
{
///
/// PLC节点号,调试方法,一般不需要使用
///
public string PLCNode
{
get { return BasicClass.plcNode.ToString(); }
}
///
/// PC节点号,调试方法,一般不需要使用
///
public string PCNode
{
get { return BasicClass.pcNode.ToString(); }
}
public bool IsConnect
{
get { return BasicClass.Client.Connected; }
}
///
/// 实例化PLC操作对象
///
public EtherNetPLC()
{
BasicClass.Client = new TcpClient();
}
///
/// 与PLC建立TCP连接
///
/// PLC的IP地址
/// 端口号,默认9600
/// 超时时间,默认3000毫秒
///
public short Link(string rIP, short rPort, short timeOut = 3000)
{
if(BasicClass.PingCheck(rIP,timeOut))
{
if(BasicClass.Client.Client==null)
{
BasicClass.Client = new TcpClient();
}
BasicClass.Client.Connect(rIP, (int)rPort);
BasicClass.Stream = BasicClass.Client.GetStream();
Thread.Sleep(10);
if (BasicClass.SendData(FinsClass.HandShake()) != 0)
{
return -1;
}
else
{
//开始读取返回信号
byte[] buffer = new byte[24];
if (BasicClass.ReceiveData(buffer) != 0)
{
return -1;
}
else
{
if (buffer[15] != 0)//TODO:这里的15号是不是ERR信息暂时不能完全肯定
return -1;
else
{
BasicClass.pcNode = buffer[19];
BasicClass.plcNode = buffer[23];
return 0;
}
}
}
}
else
{
BasicClass.Client?.Close();
//连接超时
return -1;
}
}
///
/// 关闭PLC操作对象的TCP连接
///
///
public short Close()
{
try
{
BasicClass.Stream?.Close();
BasicClass.Client?.Close();
return 0;
}
catch
{
return -1;
}
}
///
/// 读值方法(多个连续值)
///
/// 地址类型枚举
/// 起始地址
/// 地址个数
/// 返回值
///
public short ReadWords(PlcMemory mr, short ch, short cnt, out short[] reData)
{
reData = new short[(int)(cnt)];//储存读取到的数据
int num = (int)(30 + cnt * 2);//接收数据(Text)的长度,字节数
byte[] buffer = new byte[num];//用于接收数据的缓存区大小
byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Word, ch, 00, cnt);
if (BasicClass.SendData(array) == 0)
{
if (BasicClass.ReceiveData(buffer) == 0)
{
//命令返回成功,继续查询是否有错误码,然后在读取数据
bool succeed = true;
if (buffer[11] == 3)
succeed = ErrorCode.CheckHeadError(buffer[15]);
if (succeed)//no header error
{
//endcode为fins指令的返回错误码
if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
{
//完全正确的返回,开始读取返回的具体数值
for (int i = 0; i < cnt; i++)
{
//返回的数据从第30字节开始储存的,
//PLC每个字占用两个字节,且是高位在前,这和微软的默认低位在前不同
//因此无法直接使用,reData[i] = BitConverter.ToInt16(buffer, 30 + i * 2);
//先交换了高低位的位置,然后再使用BitConverter.ToInt16转换
byte[] temp = new byte[] { buffer[30 + i * 2 + 1], buffer[30 + i * 2] };
reData[i] = BitConverter.ToInt16(temp, 0);
}
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
///
/// 读单个字方法
///
///
///
///
///
public short ReadWord(PlcMemory mr, short ch, out short reData)
{
short[] temp;
reData = new short();
short re = ReadWords(mr, ch, (short)1, out temp);
if (re != 0)
return -1;
else
{
reData = temp[0];
return 0;
}
}
///
/// 写值方法(多个连续值)
///
/// 地址类型枚举
/// 起始地址
/// 地址个数
/// 写入值
///
public short WriteWords(PlcMemory mr, short ch, short cnt, short[] inData)
{
byte[] buffer = new byte[30];
byte[] arrayhead = FinsClass.FinsCmd(RorW.Write, mr, MemoryType.Word, ch, 00, cnt);//前34字节和读指令基本一直,还需要拼接下面的输入数据数组
byte[] wdata = new byte[(int)(cnt * 2)];
//转换写入值到wdata数组
for (int i = 0; i < cnt; i++)
{
byte[] temp = BitConverter.GetBytes(inData[i]);
wdata[i * 2] = temp[1];//转换为PLC的高位在前储存方式
wdata[i * 2 + 1] = temp[0];
}
//拼接写入数组
byte[] array = new byte[(int)(cnt * 2 + 34)];
arrayhead.CopyTo(array, 0);
wdata.CopyTo(array, 34);
if (BasicClass.SendData(array) == 0)
{
if (BasicClass.ReceiveData(buffer) == 0)
{
//命令返回成功,继续查询是否有错误码,然后在读取数据
bool succeed = true;
if (buffer[11] == 3)
succeed = ErrorCode.CheckHeadError(buffer[15]);
if (succeed)//no header error
{
//endcode为fins指令的返回错误码
if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
{
//完全正确的返回0
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
///
/// 写单个字方法
///
///
///
///
///
public short WriteWord(PlcMemory mr, short ch, short inData)
{
short[] temp = new short[] { inData };
short re = WriteWords(mr, ch, (short)1, temp);
if (re != 0)
return -1;
else
{
return 0;
}
}
///
/// 读值方法-按位bit(单个)
///
/// 地址类型枚举
/// 地址000.00
/// 返回开关状态枚举EtherNetPLC.BitState,0/1
///
public short GetBitState(PlcMemory mr, string ch, out short bs)
{
bs = new short();
byte[] buffer = new byte[31];//用于接收数据的缓存区大小
short cnInt = short.Parse(ch.Split('.')[0]);
short cnBit = short.Parse(ch.Split('.')[1]);
byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Bit, cnInt, cnBit, 1);
if (BasicClass.SendData(array) == 0)
{
if (BasicClass.ReceiveData(buffer) == 0)
{
//命令返回成功,继续查询是否有错误码,然后在读取数据
bool succeed = true;
if (buffer[11] == 3)
succeed = ErrorCode.CheckHeadError(buffer[15]);
if (succeed)//no header error
{
//endcode为fins指令的返回错误码
if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
{
//完全正确的返回,开始读取返回的具体数值
bs = (short)buffer[30];
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
///
/// 写值方法-按位bit(单个)
///
/// 地址类型枚举
/// 地址000.00
/// 开关状态枚举EtherNetPLC.BitState,0/1
///
public short SetBitState(PlcMemory mr, string ch, BitState bs)
{
byte[] buffer = new byte[30];
short cnInt = short.Parse(ch.Split('.')[0]);
short cnBit = short.Parse(ch.Split('.')[1]);
byte[] arrayhead = FinsClass.FinsCmd(RorW.Write, mr, MemoryType.Bit, cnInt, cnBit, 1);
byte[] array = new byte[35];
arrayhead.CopyTo(array, 0);
array[34] = (byte)bs;
if (BasicClass.SendData(array) == 0)
{
if (BasicClass.ReceiveData(buffer) == 0)
{
//命令返回成功,继续查询是否有错误码,然后在读取数据
bool succeed = true;
if (buffer[11] == 3)
succeed = ErrorCode.CheckHeadError(buffer[15]);
if (succeed)//no header error
{
//endcode为fins指令的返回错误码
if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
{
//完全正确的返回0
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
///
/// 读一个浮点数的方法,单精度,在PLC中占两个字
///
/// 地址类型枚举
/// 起始地址,会读取两个连续的地址,因为单精度在PLC中占两个字
/// 返回一个float型
///
public short ReadReal(PlcMemory mr, short ch,out float reData)
{
reData = new float();
int num = (int)(30 + 2 * 2);//接收数据(Text)的长度,字节数
byte[] buffer = new byte[num];//用于接收数据的缓存区大小
byte[] array = FinsClass.FinsCmd(RorW.Read, mr, MemoryType.Word, ch, 00, 2);
if (BasicClass.SendData(array) == 0)
{
if (BasicClass.ReceiveData(buffer) == 0)
{
//命令返回成功,继续查询是否有错误码,然后在读取数据
bool succeed = true;
if (buffer[11] == 3)
succeed = ErrorCode.CheckHeadError(buffer[15]);
if (succeed)//no header error
{
//endcode为fins指令的返回错误码
if (ErrorCode.CheckEndCode(buffer[28], buffer[29]))
{
//完全正确的返回,开始读取返回的具体数值
byte[] temp = new byte[] { buffer[30 + 1], buffer[30], buffer[30 + 3], buffer[30 + 2] };
reData = BitConverter.ToSingle(temp, 0);
return 0;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
else
{
return -1;
}
}
}
}