package com.zy.common.HslCommunication.Profinet.Siemens; import com.zy.common.HslCommunication.BasicFramework.SoftBasic; import com.zy.common.HslCommunication.Core.IMessage.FetchWriteMessage; import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; import com.zy.common.HslCommunication.Core.Transfer.ReverseBytesTransform; import com.zy.common.HslCommunication.Core.Types.OperateResult; import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; import com.zy.common.HslCommunication.Core.Types.OperateResultExThree; import com.zy.common.HslCommunication.StringResources; /** * 使用了Fetch/Write协议来和西门子进行通讯,该种方法需要在PLC侧进行一些配置 */ public class SiemensFetchWriteNet extends NetworkDeviceBase { /** * 实例化一个西门子的Fetch/Write协议的通讯对象 */ public SiemensFetchWriteNet() { WordLength = 2; } /** * 实例化一个西门子的Fetch/Write协议的通讯对象 * * @param ipAddress PLC的Ip地址 * @param port PLC的端口 */ public SiemensFetchWriteNet(String ipAddress, int port) { WordLength = 2; setIpAddress(ipAddress); setPort(port); } /** * 从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,T100,C100,以字节为单位 * * @param address 起始地址,格式为I100,M100,Q100,DB20.100,T100,C100 * @param length 读取的数量,以字节为单位 * @return 带有成功标志的字节信息 */ @Override public OperateResultExOne Read(String address, short length) { OperateResultExOne result = new OperateResultExOne(); OperateResultExOne command = BuildReadCommand(address, length); if (!command.IsSuccess) { result.CopyErrorFromOther(command); return result; } OperateResultExOne read = ReadFromCoreServer(command.Content); if (read.IsSuccess) { if (read.Content[8] == 0x00) { // 分析结果 byte[] buffer = new byte[read.Content.length - 16]; System.arraycopy(read.Content, 16, buffer, 0, buffer.length); result.Content = buffer; result.IsSuccess = true; } else { result.ErrorCode = read.Content[8]; result.Message = "发生了异常,具体信息查找Fetch/Write协议文档"; } } else { result.ErrorCode = read.ErrorCode; result.Message = read.Message; } return result; } /** * 读取指定地址的byte数据 * * @param address 起始地址,格式为I100,M100,Q100,DB20.100 * @return 返回写入结果 */ public OperateResultExOne ReadByte(String address) { return GetByteResultFromBytes(Read(address, (short) 1)); } /** * 将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位 * * @param address 起始地址,格式为I100,M100,Q100,DB20.100 * @param value 写入的数据,长度根据data的长度来指示 * @return 返回写入结果 */ @Override public OperateResult Write(String address, byte[] value) { OperateResult result = new OperateResult(); OperateResultExOne command = BuildWriteCommand(address, value); if (!command.IsSuccess) { result.CopyErrorFromOther(command); return result; } OperateResultExOne write = ReadFromCoreServer(command.Content); if (write.IsSuccess) { if (write.Content[8] != 0x00) { // 写入异常 result.Message = "写入数据异常,代号为:" + String.valueOf(write.Content[8]); } else { result.IsSuccess = true; // 写入成功 } } else { result.ErrorCode = write.ErrorCode; result.Message = write.Message; } return result; } /** * 向PLC中写入bool数组,返回值说明,比如你写入M100,那么data[0]对应M100.0 * * @param address 要写入的数据地址 * @param values 要写入的实际数据,长度为8的倍数 * @return 返回写入结果 */ public OperateResult Write(String address, boolean[] values) { return Write(address, SoftBasic.BoolArrayToByte(values)); } /** * 向PLC中写入byte数据,返回值说明 * * @param address 要写入的数据地址 * @param value 要写入的实际数据 * @return 返回写入结果 */ public OperateResult Write(String address, byte value) { return Write(address, new byte[]{value}); } /** * 返回表示当前对象的字符串 * * @return 字符串 */ @Override public String toString() { return "SiemensFetchWriteNet"; } /** * 计算特殊的地址信息 * * @param address 字符串信息 * @return 实际值 */ public static int CalculateAddressStarted(String address) { if (address.indexOf('.') < 0) { return Integer.parseInt(address); } else { String[] temp = address.split("\\."); return Integer.parseInt(temp[0]); } } /** * 解析数据地址,解析出地址类型,起始地址,DB块的地址 * * @param address 数据地址 * @return 解析出地址类型,起始地址,DB块的地址 */ public static OperateResultExThree AnalysisAddress(String address) { OperateResultExThree result = new OperateResultExThree(); try { result.Content3 = 0; if (address.indexOf(0) == 'I') { result.Content1 = 0x03; result.Content2 = CalculateAddressStarted(address.substring(1)); } else if (address.indexOf(0) == 'Q') { result.Content1 = 0x04; result.Content2 = CalculateAddressStarted(address.substring(1)); } else if (address.indexOf(0) == 'M') { result.Content1 = 0x02; result.Content2 = CalculateAddressStarted(address.substring(1)); } else if (address.indexOf(0) == 'D' || address.substring(0, 2).equals("DB")) { result.Content1 = 0x01; String[] adds = address.split("\\."); if (address.indexOf(1) == 'B') { result.Content3 = Integer.parseInt(adds[0].substring(2)); } else { result.Content3 = Integer.parseInt(adds[0].substring(1)); } if (result.Content3 > 255) { result.Message = StringResources.Language.SiemensDBAddressNotAllowedLargerThan255(); return result; } result.Content2 = CalculateAddressStarted(address.substring(address.indexOf('.') + 1)); } else if (address.indexOf(0) == 'T') { result.Content1 = 0x07; result.Content2 = CalculateAddressStarted(address.substring(1)); } else if (address.indexOf(0) == 'C') { result.Content1 = 0x06; result.Content2 = CalculateAddressStarted(address.substring(1)); } else { return new OperateResultExThree(StringResources.Language.NotSupportedDataType()); } } catch (Exception ex) { result.Message = ex.getMessage(); return result; } result.IsSuccess = true; return result; } /** * 生成一个读取字数据指令头的通用方法 * * @param address 地址 * @param count 长度 * @return 带结果标识的指令 */ public static OperateResultExOne BuildReadCommand(String address, int count) { OperateResultExThree analysis = AnalysisAddress(address); if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); byte[] _PLCCommand = new byte[16]; _PLCCommand[0] = 0x53; _PLCCommand[1] = 0x35; _PLCCommand[2] = 0x10; _PLCCommand[3] = 0x01; _PLCCommand[4] = 0x03; _PLCCommand[5] = 0x05; _PLCCommand[6] = 0x03; _PLCCommand[7] = 0x08; // 指定数据区 _PLCCommand[8] = analysis.Content1; _PLCCommand[9] = analysis.Content3.byteValue(); // 指定数据地址 _PLCCommand[10] = (byte) (analysis.Content2 / 256); _PLCCommand[11] = (byte) (analysis.Content2 % 256); if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07) { if (count % 2 != 0) { return new OperateResultExOne(StringResources.Language.SiemensReadLengthMustBeEvenNumber()); } else { // 指定数据长度 _PLCCommand[12] = (byte) (count / 2 / 256); _PLCCommand[13] = (byte) (count / 2 % 256); } } else { // 指定数据长度 _PLCCommand[12] = (byte) (count / 256); _PLCCommand[13] = (byte) (count % 256); } _PLCCommand[14] = (byte) 0xff; _PLCCommand[15] = 0x02; return OperateResultExOne.CreateSuccessResult(_PLCCommand); } /** * 生成一个写入字节数据的指令 * * @param address 地址 * @param data 数据 * @return 带结果标识的指令 */ public static OperateResultExOne BuildWriteCommand(String address, byte[] data) { if (data == null) data = new byte[0]; OperateResultExThree analysis = AnalysisAddress(address); if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); byte[] _PLCCommand = new byte[16 + data.length]; _PLCCommand[0] = 0x53; _PLCCommand[1] = 0x35; _PLCCommand[2] = 0x10; _PLCCommand[3] = 0x01; _PLCCommand[4] = 0x03; _PLCCommand[5] = 0x03; _PLCCommand[6] = 0x03; _PLCCommand[7] = 0x08; // 指定数据区 _PLCCommand[8] = analysis.Content1; _PLCCommand[9] = analysis.Content3.byteValue(); // 指定数据地址 _PLCCommand[10] = (byte) (analysis.Content2 / 256); _PLCCommand[11] = (byte) (analysis.Content2 % 256); if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07) { if (data.length % 2 != 0) { return new OperateResultExOne(StringResources.Language.SiemensReadLengthMustBeEvenNumber()); } else { // 指定数据长度 _PLCCommand[12] = (byte) (data.length / 2 / 256); _PLCCommand[13] = (byte) (data.length / 2 % 256); } } else { // 指定数据长度 _PLCCommand[12] = (byte) (data.length / 256); _PLCCommand[13] = (byte) (data.length % 256); } _PLCCommand[14] = (byte) 0xff; _PLCCommand[15] = 0x02; // 放置数据 System.arraycopy(data, 0, _PLCCommand, 16, data.length); return OperateResultExOne.CreateSuccessResult(_PLCCommand); } }