6个文件已修改
34个文件已添加
6个文件已删除
37 文件已重命名
File was renamed from src/main/java/com/zy/gateway/core/base/SoftBasic.java |
| | |
| | | package com.zy.gateway.core.base; |
| | | package com.zy.common.HslCommunication.BasicFramework; |
| | | |
| | | |
| | | import java.io.ByteArrayOutputStream; |
New file |
| | |
| | | package com.zy.common.HslCommunication.BasicFramework; |
| | | |
| | | import java.util.concurrent.locks.Lock; |
| | | import java.util.concurrent.locks.ReentrantLock; |
| | | |
| | | /** |
| | | * 一个简单的不持久化的序号自增类,采用线程安全实现,并允许指定最大数字,到达后清空从指定数开始 |
| | | */ |
| | | public class SoftIncrementCount { |
| | | |
| | | |
| | | /** |
| | | * 实例化一个自增信息的对象,包括最大值 |
| | | * @param max 数据的最大值,必须指定 |
| | | * @param start 数据的起始值,默认为0 |
| | | */ |
| | | public SoftIncrementCount( long max, long start ) |
| | | { |
| | | this.start = start; |
| | | this.max = max; |
| | | current = start; |
| | | hybirdLock = new ReentrantLock(); |
| | | } |
| | | |
| | | |
| | | private long start = 0; |
| | | private long current = 0; |
| | | private long max = Long.MAX_VALUE; |
| | | private Lock hybirdLock; |
| | | |
| | | |
| | | /** |
| | | * 获取自增信息 |
| | | * @return 值 |
| | | */ |
| | | public long GetCurrentValue( ) |
| | | { |
| | | long value = 0; |
| | | hybirdLock.lock( ); |
| | | |
| | | value = current; |
| | | current++; |
| | | if (current > max) |
| | | { |
| | | current = 0; |
| | | } |
| | | |
| | | hybirdLock.unlock( ); |
| | | return value; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.BasicFramework; |
| | | |
| | | |
| | | public class SoftSecurity { |
| | | |
| | | |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/base/SoftZipped.java |
| | |
| | | package com.zy.gateway.core.base; |
| | | package com.zy.common.HslCommunication.BasicFramework; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.ByteArrayOutputStream; |
New file |
| | |
| | | package com.zy.common.HslCommunication.BasicFramework; |
| | | |
| | | /** |
| | | * 系统的版本类 |
| | | */ |
| | | public class SystemVersion { |
| | | |
| | | /** |
| | | * 根据格式化字符串的版本号初始化 |
| | | * @param VersionString 格式化的字符串,例如:1.0.0或1.0.0.0503 |
| | | */ |
| | | public SystemVersion(String VersionString) |
| | | { |
| | | String[] temp = VersionString.split("\\."); |
| | | if (temp.length >= 3) |
| | | { |
| | | m_MainVersion = Integer.parseInt(temp[0]); |
| | | m_SecondaryVersion = Integer.parseInt(temp[1]); |
| | | m_EditVersion = Integer.parseInt(temp[2]); |
| | | |
| | | if (temp.length >= 4) |
| | | { |
| | | m_InnerVersion = Integer.parseInt(temp[3]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据指定的数字实例化一个对象 |
| | | * @param main 主版本 |
| | | * @param sec 次版本 |
| | | * @param edit 修订版 |
| | | */ |
| | | public SystemVersion(int main, int sec, int edit) |
| | | { |
| | | m_MainVersion = main; |
| | | m_SecondaryVersion = sec; |
| | | m_EditVersion = edit; |
| | | } |
| | | |
| | | /** |
| | | * 根据指定的数字实例化一个对象 |
| | | * @param main 主版本 |
| | | * @param sec 次版本 |
| | | * @param edit 修订版 |
| | | * @param inner 内部版本号 |
| | | */ |
| | | public SystemVersion(int main, int sec, int edit, int inner) |
| | | { |
| | | m_MainVersion = main; |
| | | m_SecondaryVersion = sec; |
| | | m_EditVersion = edit; |
| | | m_InnerVersion = inner; |
| | | } |
| | | private int m_MainVersion = 2; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 主版本 |
| | | * @return int数据 |
| | | */ |
| | | public int MainVersion() |
| | | { |
| | | return m_MainVersion; |
| | | } |
| | | |
| | | private int m_SecondaryVersion = 0; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 次版本 |
| | | * @return int数据 |
| | | */ |
| | | public int SecondaryVersion() { |
| | | return m_SecondaryVersion; |
| | | } |
| | | |
| | | private int m_EditVersion = 0; |
| | | |
| | | /** |
| | | * 修订版 |
| | | * @return int数据 |
| | | */ |
| | | public int EditVersion() { |
| | | return m_EditVersion; |
| | | } |
| | | private int m_InnerVersion = 0; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 内部版本号,或者是版本号表示为年月份+内部版本的表示方式 |
| | | * @return int数据 |
| | | */ |
| | | public int InnerVersion() |
| | | { |
| | | return m_InnerVersion; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据格式化为支持返回的不同信息的版本号 |
| | | * C返回1.0.0.0 |
| | | * N返回1.0.0 |
| | | * S返回1.0 |
| | | * @param format 格式化信息 |
| | | * @return 字符串数据 |
| | | */ |
| | | public String toString(String format) |
| | | { |
| | | if(format == "C") |
| | | { |
| | | return MainVersion()+"."+SecondaryVersion()+"."+EditVersion()+"."+InnerVersion(); |
| | | } |
| | | |
| | | if(format == "N") |
| | | { |
| | | return MainVersion()+"."+SecondaryVersion()+"."+EditVersion(); |
| | | } |
| | | |
| | | if(format == "S") |
| | | { |
| | | return MainVersion()+"."+SecondaryVersion(); |
| | | } |
| | | |
| | | return toString(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 版本信息 |
| | | * @return 字符串数据 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | if(InnerVersion() == 0) |
| | | { |
| | | return MainVersion()+"."+SecondaryVersion()+"."+EditVersion(); |
| | | } |
| | | else |
| | | { |
| | | return MainVersion()+"."+SecondaryVersion()+"."+EditVersion()+"."+InnerVersion(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 判断版本是否一致 |
| | | * @param sv 对比的版本 |
| | | * @return 是否一致 |
| | | */ |
| | | public boolean IsSameVersion(SystemVersion sv) { |
| | | if (this.m_MainVersion != sv.m_MainVersion) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.m_SecondaryVersion != sv.m_SecondaryVersion) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.m_EditVersion != sv.m_EditVersion) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.m_InnerVersion != sv.m_InnerVersion) { |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 判断是不是小于指定的版本 |
| | | * @param sv 对比的版本 |
| | | * @return 是否小于 |
| | | */ |
| | | public boolean IsSmallerThan(SystemVersion sv) { |
| | | if (this.m_MainVersion < sv.m_MainVersion) { |
| | | return true; |
| | | } |
| | | else if(this.m_MainVersion > sv.m_MainVersion) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.m_SecondaryVersion < sv.m_SecondaryVersion) { |
| | | return true; |
| | | } |
| | | else if (this.m_SecondaryVersion > sv.m_SecondaryVersion) { |
| | | return false; |
| | | |
| | | } |
| | | |
| | | if (this.m_EditVersion < sv.m_EditVersion) { |
| | | return true; |
| | | } |
| | | else if (this.m_EditVersion > sv.m_EditVersion) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.m_InnerVersion < sv.m_InnerVersion) { |
| | | return true; |
| | | } |
| | | else if (this.m_InnerVersion > sv.m_InnerVersion) { |
| | | return false; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.Address; |
| | | |
| | | /** |
| | | * 所有通信类的地址基类 |
| | | */ |
| | | public class DeviceAddressBase { |
| | | |
| | | |
| | | /** |
| | | * 获取地址信息 |
| | | * @return |
| | | */ |
| | | public int getAddress() { |
| | | return Address; |
| | | } |
| | | |
| | | /** |
| | | * 设置地址信息 |
| | | * @param address |
| | | */ |
| | | public void setAddress(int address) { |
| | | Address = address; |
| | | } |
| | | |
| | | /** |
| | | * 起始地址 |
| | | */ |
| | | private int Address = 0; |
| | | |
| | | |
| | | /** |
| | | * 解析字符串的地址 |
| | | * |
| | | * @param address |
| | | */ |
| | | public void AnalysisAddress(String address) { |
| | | Address = Integer.parseInt(address); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * @return 字符串 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return String.valueOf(Address); |
| | | } |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | public class FetchWriteMessage implements INetMessage |
| | | { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 16; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | |
| | | if(SendBytes == null) return 16; |
| | | |
| | | if(HeadBytes[5]==0x04) |
| | | { |
| | | return 0; |
| | | } |
| | | else { |
| | | return (HeadBytes[12] & 0xff) * 256 + (HeadBytes[13] & 0xff); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if(HeadBytes == null) return false; |
| | | if(HeadBytes[0]==0x53 && HeadBytes[1] == 0x35){ |
| | | return true; |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return HeadBytes[3]; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | public class FinsMessage implements INetMessage |
| | | { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 8; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | |
| | | byte[] buffer = new byte[4]; |
| | | buffer[0] = HeadBytes[7]; |
| | | buffer[1] = HeadBytes[6]; |
| | | buffer[2] = HeadBytes[5]; |
| | | buffer[3] = HeadBytes[4]; |
| | | return Utilities.getInt(buffer,0); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if(HeadBytes == null) return false; |
| | | if(HeadBytes[0] == 0x46 && HeadBytes[1] == 0x49 && HeadBytes[2] == 0x4E && HeadBytes[3] == 0x53){ |
| | | return true; |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * 本组件系统使用的默认的消息规则,说明解析和反解析规则的 |
| | | */ |
| | | public class HslMessage implements INetMessage |
| | | { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 32; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | if(HeadBytes.length != 32) return 0; |
| | | |
| | | return Utilities.getInt(HeadBytes,28); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token){ |
| | | return SoftBasic.IsTwoBytesEquel(HeadBytes,12,token,0,16); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return Utilities.getInt(HeadBytes,0); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/domain/siemens/INetMessage.java |
| | |
| | | package com.zy.gateway.core.domain.siemens; |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | /** |
| | | * 本系统的消息类,包含了各种解析规则,数据信息提取规则 |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | public class MelsecA1EBinaryMessage implements INetMessage { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 2; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | |
| | | int contentLength = 0; |
| | | |
| | | if (HeadBytes[1] == 0x5B) |
| | | { |
| | | contentLength = 2; //结束代码 + 0x00 |
| | | return contentLength; |
| | | } |
| | | else |
| | | { |
| | | int length = (SendBytes[10] % 2 == 0) ? SendBytes[10] : SendBytes[10] + 1; |
| | | switch (HeadBytes[0]) |
| | | { |
| | | case (byte) 0x80: //位单位成批读出后,回复副标题 |
| | | contentLength = length / 2; |
| | | break; |
| | | case (byte) 0x81: //字单位成批读出后,回复副标题 |
| | | contentLength = SendBytes[10] * 2; |
| | | break; |
| | | case (byte) 0x82: //位单位成批写入后,回复副标题 |
| | | break; |
| | | case (byte) 0x83: //字单位成批写入后,回复副标题 |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | // 在A兼容1E协议中,写入值后,若不发生异常,只返回副标题 + 结束代码(0x00) |
| | | // 这已经在协议头部读取过了,后面要读取的长度为0(contentLength=0) |
| | | } |
| | | return contentLength; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if (HeadBytes != null) |
| | | { |
| | | if ((HeadBytes[0] - SendBytes[0]) == (byte) 0x80) { return true; } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | public class MelsecQnA3EAsciiMessage implements INetMessage |
| | | { |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 18; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | |
| | | byte[] buffer = new byte[4]; |
| | | buffer[0] = HeadBytes[14]; |
| | | buffer[1] = HeadBytes[15]; |
| | | buffer[2] = HeadBytes[16]; |
| | | buffer[3] = HeadBytes[17]; |
| | | |
| | | return Integer.parseInt(Utilities.getString(buffer,"ascii"),16); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if(HeadBytes == null) return false; |
| | | if(HeadBytes[0] == (byte)'D' && HeadBytes[1] == (byte)'0' && HeadBytes[2] == (byte)'0' && HeadBytes[3] == (byte)'0'){ |
| | | return true; |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | public class MelsecQnA3EBinaryMessage implements INetMessage |
| | | { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 9; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes(){ |
| | | if(HeadBytes == null) return 0; |
| | | |
| | | return (HeadBytes[7]&0xff) + (HeadBytes[8]&0xff)*256; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if(HeadBytes == null) return false; |
| | | if((HeadBytes[0]&0xff)==0xd0 && HeadBytes[1] == 0x00){ |
| | | return true; |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | |
| | | /** |
| | | * Modbus Tcp协议的消息对象,用来确定接收规则的 |
| | | */ |
| | | public class ModbusTcpMessage implements INetMessage |
| | | { |
| | | |
| | | /** |
| | | * 消息头的指令长度 |
| | | */ |
| | | public int ProtocolHeadBytesLength(){ |
| | | return 8; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从当前的头子节文件中提取出接下来需要接收的数据长度 |
| | | * @return 返回接下来的数据内容长度 |
| | | */ |
| | | public int GetContentLengthByHeadBytes() { |
| | | if (HeadBytes == null) return 0; |
| | | if (HeadBytes.length >= ProtocolHeadBytesLength()) { |
| | | int length = (HeadBytes[4] & 0xff) * 256 + (HeadBytes[5] & 0xff); |
| | | if (length == 0) { |
| | | byte[] buffer = new byte[ProtocolHeadBytesLength() - 1]; |
| | | for (int i = 0; i < buffer.length; i++) { |
| | | buffer[i] = HeadBytes[i + 1]; |
| | | } |
| | | HeadBytes = buffer; |
| | | return (HeadBytes[5] & 0xff) * 256 + (HeadBytes[6] & 0xff) - 1; |
| | | } else { |
| | | return length - 2; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查头子节的合法性 |
| | | * @param token 特殊的令牌,有些特殊消息的验证 |
| | | * @return 是否合法的验证 |
| | | */ |
| | | public boolean CheckHeadBytesLegal(byte[] token) |
| | | { |
| | | if(HeadBytes == null) return false; |
| | | if(HeadBytes[2]==0x00 && HeadBytes[3] == 0x00){ |
| | | return true; |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取头子节里的消息标识 |
| | | * @return |
| | | */ |
| | | public int GetHeadBytesIdentity(){ |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息头字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getHeadBytes() { |
| | | return HeadBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息内容字节 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getContentBytes() { |
| | | return ContentBytes; |
| | | } |
| | | |
| | | /** |
| | | * 获取发送的消息 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public byte[] getSendBytes() { |
| | | return SendBytes; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息头子节 |
| | | * @param headBytes 字节数据 |
| | | */ |
| | | public void setHeadBytes(byte[] headBytes){ |
| | | HeadBytes = headBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置消息内容字节 |
| | | * @param contentBytes 内容字节 |
| | | */ |
| | | public void setContentBytes(byte[] contentBytes){ |
| | | ContentBytes = contentBytes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 设置发送的字节信息 |
| | | * @param sendBytes 发送的字节信息 |
| | | */ |
| | | public void setSendBytes(byte[] sendBytes){ |
| | | SendBytes = sendBytes; |
| | | } |
| | | |
| | | |
| | | private byte[] HeadBytes = null; |
| | | |
| | | private byte[] ContentBytes = null; |
| | | |
| | | private byte[] SendBytes = null; |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/domain/siemens/S7Message.java |
| | |
| | | package com.zy.gateway.core.domain.siemens; |
| | | package com.zy.common.HslCommunication.Core.IMessage; |
| | | |
| | | public class S7Message implements INetMessage { |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/net/HslProtocol.java |
| | |
| | | package com.zy.gateway.core.net; |
| | | package com.zy.common.HslCommunication.Core.Net; |
| | | |
| | | import com.zy.gateway.core.base.HslSecurity; |
| | | import com.zy.gateway.core.base.SoftZipped; |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.BasicFramework.*; |
| | | import com.zy.common.HslCommunication.Core.Security.HslSecurity; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.util.UUID; |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/net/IReadWriteNet.java |
| | |
| | | package com.zy.gateway.core.net; |
| | | package com.zy.common.HslCommunication.Core.Net; |
| | | |
| | | import com.zy.gateway.core.domain.IDataTransfer; |
| | | import com.zy.gateway.core.domain.OperateResult; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.IDataTransfer; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | |
| | | /** |
| | | * 所有设备交互类的统一的读写接口 |
| | |
| | | * @param length 数据长度 |
| | | * @return 带有成功标识的byte[]数组 |
| | | */ |
| | | OperateResultExOne<byte[]> Read(String address, short length); |
| | | OperateResultExOne<byte[]> Read(String address, short length ); |
| | | |
| | | /** |
| | | * 读取16位的有符号整型 |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return 带有成功标识的short数组 |
| | | */ |
| | | OperateResultExOne<short []> ReadInt16(String address, short length); |
| | | OperateResultExOne<short []> ReadInt16( String address, short length ); |
| | | |
| | | /** |
| | | * 读取32位的有符号整型 |
| | |
| | | * @param length 数组长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | OperateResultExOne<int[]> ReadInt32(String address, short length); |
| | | OperateResultExOne<int[]> ReadInt32( String address, short length ); |
| | | |
| | | /** |
| | | * 读取64位的有符号整型 |
| | |
| | | * @param length 数组长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | OperateResultExOne<long[]> ReadInt64(String address, short length); |
| | | OperateResultExOne<long[]> ReadInt64( String address, short length ); |
| | | |
| | | /** |
| | | * 读取单浮点精度的数据 |
| | |
| | | * @param length 数组长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | OperateResultExOne<float[]> ReadFloat(String address, short length); |
| | | OperateResultExOne<float[]> ReadFloat( String address, short length ); |
| | | |
| | | /** |
| | | * 读取双浮点精度的数据 |
| | |
| | | * @param length 数组长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | OperateResultExOne<double[]> ReadDouble(String address, short length); |
| | | OperateResultExOne<double[]> ReadDouble( String address, short length ); |
| | | |
| | | /** |
| | | * 读取字符串数据 |
| | |
| | | * @param <T> 自定义的类型 |
| | | * @return 带有成功标识的自定义类型数据 |
| | | */ |
| | | <T extends IDataTransfer> OperateResultExOne<T> ReadCustomer(String address, Class<T> tClass); |
| | | <T extends IDataTransfer> OperateResultExOne<T> ReadCustomer(String address,Class<T> tClass); |
| | | |
| | | |
| | | |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.Net; |
| | | |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | |
| | | /** |
| | | * 用于通信过程中的暗号对象 |
| | | */ |
| | | public final class NetHandle { |
| | | |
| | | |
| | | /** |
| | | * 初始化一个暗号对象 |
| | | * @param value int值 |
| | | */ |
| | | public NetHandle(int value) |
| | | { |
| | | byte[] buffer = Utilities.getBytes(value); |
| | | |
| | | m_CodeMajor = buffer[3]; |
| | | m_CodeMinor = buffer[2]; |
| | | m_CodeIdentifier = Utilities.getShort(buffer,0); |
| | | |
| | | |
| | | m_CodeValue = value; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据三个值来初始化暗号对象 |
| | | * @param major 主暗号 |
| | | * @param minor 主暗号 |
| | | * @param identifier 暗号编号 |
| | | */ |
| | | public NetHandle(int major, int minor, int identifier) |
| | | { |
| | | m_CodeValue = 0; |
| | | |
| | | byte[] buffer_major=Utilities.getBytes(major); |
| | | byte[] buffer_minor=Utilities.getBytes(minor); |
| | | byte[] buffer_identifier=Utilities.getBytes(identifier); |
| | | |
| | | m_CodeMajor = buffer_major[0]; |
| | | m_CodeMinor = buffer_minor[0]; |
| | | m_CodeIdentifier = Utilities.getShort(buffer_identifier,0); |
| | | |
| | | byte[] buffer = new byte[4]; |
| | | buffer[3] = m_CodeMajor; |
| | | buffer[2] = m_CodeMinor; |
| | | buffer[1] = buffer_identifier[1]; |
| | | buffer[0] = buffer_identifier[0]; |
| | | |
| | | m_CodeValue = Utilities.getInt(buffer,0); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 完整的暗号值 |
| | | */ |
| | | private int m_CodeValue; |
| | | |
| | | /** |
| | | * 主暗号分类0-255 |
| | | */ |
| | | private byte m_CodeMajor; |
| | | |
| | | /** |
| | | * 次要的暗号分类0-255 |
| | | */ |
| | | private byte m_CodeMinor; |
| | | |
| | | /** |
| | | * 暗号的编号分类0-65535 |
| | | */ |
| | | private short m_CodeIdentifier; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取完整的暗号值 |
| | | * @return |
| | | */ |
| | | public int get_CodeValue(){ |
| | | return m_CodeValue; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取主暗号分类0-255 |
| | | * @return 主暗号 |
| | | */ |
| | | public byte get_CodeMajor() { |
| | | return m_CodeMajor; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取次要的暗号分类0-255 |
| | | * @return 次暗号 |
| | | */ |
| | | public byte get_CodeMinor() { |
| | | return m_CodeMinor; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取暗号的编号分类0-65535 |
| | | * @return 编号分类 |
| | | */ |
| | | public short get_CodeIdentifier() { |
| | | return m_CodeIdentifier; |
| | | } |
| | | |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/net/NetworkBase.java |
| | |
| | | package com.zy.gateway.core.net; |
| | | package com.zy.common.HslCommunication.Core.Net.NetworkBase; |
| | | |
| | | import com.zy.gateway.core.StringResources; |
| | | import com.zy.gateway.core.domain.HslTimeOut; |
| | | import com.zy.gateway.core.domain.OperateResult; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.gateway.core.domain.siemens.INetMessage; |
| | | import com.zy.gateway.core.log.ILogNet; |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.Core.IMessage.INetMessage; |
| | | import com.zy.common.HslCommunication.Core.Types.HslTimeOut; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.LogNet.Core.ILogNet; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.io.DataOutputStream; |
| | | import java.io.IOException; |
File was renamed from src/main/java/com/zy/gateway/core/net/NetworkDeviceBase.java |
| | |
| | | package com.zy.gateway.core.net; |
| | | package com.zy.common.HslCommunication.Core.Net.NetworkBase; |
| | | |
| | | import com.zy.gateway.core.base.SoftBasic; |
| | | import com.zy.gateway.core.domain.IDataTransfer; |
| | | import com.zy.gateway.core.domain.OperateResult; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.gateway.core.domain.siemens.INetMessage; |
| | | import com.zy.gateway.core.transfer.IByteTransform; |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.IMessage.INetMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.IReadWriteNet; |
| | | import com.zy.common.HslCommunication.Core.Transfer.IByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.IDataTransfer; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | |
| | | /** |
| | |
| | | * @param <T> 类型名称 |
| | | * @return 带有成功标识的结果对象 |
| | | */ |
| | | public <T extends IDataTransfer> OperateResultExOne<T> ReadCustomer(String address , Class<T> tClass) |
| | | public <T extends IDataTransfer> OperateResultExOne<T> ReadCustomer(String address ,Class<T> tClass) |
| | | { |
| | | OperateResultExOne<T> result = new OperateResultExOne<T>(); |
| | | T Content; |
File was renamed from src/main/java/com/zy/gateway/core/net/NetworkDoubleBase.java |
| | |
| | | package com.zy.gateway.core.net; |
| | | package com.zy.common.HslCommunication.Core.Net.NetworkBase; |
| | | |
| | | import com.zy.gateway.core.StringResources; |
| | | import com.zy.gateway.core.base.SoftBasic; |
| | | import com.zy.gateway.core.domain.OperateResult; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.gateway.core.domain.OperateResultExTwo; |
| | | import com.zy.gateway.core.domain.siemens.INetMessage; |
| | | import com.zy.gateway.core.net.session.AlienSession; |
| | | import com.zy.gateway.core.transfer.ByteTransformHelper; |
| | | import com.zy.gateway.core.transfer.IByteTransform; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.IMessage.INetMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.StateOne.AlienSession; |
| | | import com.zy.common.HslCommunication.Core.Transfer.ByteTransformHelper; |
| | | import com.zy.common.HslCommunication.Core.Transfer.IByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | |
| | | import java.lang.reflect.ParameterizedType; |
| | | import java.net.Socket; |
| | |
| | | * @param <TNetMessage> 消息类的类型 |
| | | * @param <TTransform> 转换类的类型 |
| | | */ |
| | | public class NetworkDoubleBase<TNetMessage extends INetMessage,TTransform extends IByteTransform> extends NetworkBase |
| | | public class NetworkDoubleBase<TNetMessage extends INetMessage ,TTransform extends IByteTransform> extends NetworkBase |
| | | { |
| | | /** |
| | | * 默认的无参构造函数 |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.Net.NetworkBase; |
| | | |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.Net.HslProtocol; |
| | | import com.zy.common.HslCommunication.Core.Net.StateOne.AppSession; |
| | | import com.zy.common.HslCommunication.Core.Types.*; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.io.File; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.net.Socket; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 客户端服务器的共享基类 |
| | | */ |
| | | public class NetworkXBase extends NetworkBase |
| | | { |
| | | |
| | | /** |
| | | * 默认的无参构造方法 |
| | | */ |
| | | public NetworkXBase() |
| | | { |
| | | } |
| | | |
| | | /** |
| | | * 发送数据的方法 |
| | | * @param session 通信用的核心对象 |
| | | * @param content 完整的字节信息 |
| | | */ |
| | | void SendBytesAsync(AppSession session, byte[] content ) |
| | | { |
| | | if (content == null) return; |
| | | try |
| | | { |
| | | // 进入发送数据的锁,然后开启异步的数据发送 |
| | | session.getHybirdLockSend().lock(); |
| | | OutputStream outputStream = session.getWorkSocket().getOutputStream(); |
| | | outputStream.write(content); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | if (!ex.getMessage().contains( StringResources.Language.SocketRemoteCloseException() )) |
| | | { |
| | | if(LogNet!=null) LogNet.WriteException( toString( ), StringResources.Language.SocketSendException(), ex ); |
| | | } |
| | | } |
| | | finally { |
| | | session.getHybirdLockSend().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | private Thread thread; // 后台线程 |
| | | |
| | | /** |
| | | * 开始接受数据 |
| | | * @param session 会话信息 |
| | | */ |
| | | protected void BeginReceiveBackground(AppSession session){ |
| | | thread = new Thread(){ |
| | | @Override |
| | | public void run(){ |
| | | while (true){ |
| | | OperateResultExOne<byte[]> readHeadBytes = Receive(session.getWorkSocket(),HslProtocol.HeadByteLength); |
| | | if(!readHeadBytes.IsSuccess){ |
| | | SocketReceiveException( session ); |
| | | return; |
| | | } |
| | | |
| | | int length = Utilities.getInt(readHeadBytes.Content,28); |
| | | OperateResultExOne<byte[]> readContent = Receive(session.getWorkSocket(),length); |
| | | if(!readContent.IsSuccess){ |
| | | SocketReceiveException( session ); |
| | | return; |
| | | } |
| | | |
| | | if (CheckRemoteToken( readHeadBytes.Content )) |
| | | { |
| | | byte[] head = readHeadBytes.Content; |
| | | byte[] content = HslProtocol.CommandAnalysis(head,readContent.Content); |
| | | int protocol = Utilities.getInt( head, 0 ); |
| | | int customer = Utilities.getInt( head, 4 ); |
| | | |
| | | DataProcessingCenter(session,protocol,customer,content); |
| | | } |
| | | else { |
| | | if(LogNet!=null) LogNet.WriteWarn( toString( ), StringResources.Language.TokenCheckFailed() ); |
| | | AppSessionRemoteClose( session ); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | thread.start(); |
| | | } |
| | | |
| | | /** |
| | | * 数据处理中心,应该继承重写 |
| | | * @param session 连接状态 |
| | | * @param protocol 协议头 |
| | | * @param customer 用户自定义 |
| | | * @param content 数据内容 |
| | | */ |
| | | protected void DataProcessingCenter( AppSession session, int protocol, int customer, byte[] content ) { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 检查当前的头子节信息的令牌是否是正确的 |
| | | * @param headBytes 头子节数据 |
| | | * @return 令牌是验证成功 |
| | | */ |
| | | protected boolean CheckRemoteToken( byte[] headBytes ) |
| | | { |
| | | return SoftBasic.IsTwoBytesEquel( headBytes,12, Utilities.UUID2Byte(Token),0,16 ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 接收出错的时候进行处理 |
| | | * @param session 会话内容 |
| | | */ |
| | | protected void SocketReceiveException( AppSession session ) { |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 当远端的客户端关闭连接时触发 |
| | | * @param session 会话内容 |
| | | */ |
| | | protected void AppSessionRemoteClose( AppSession session ) { |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * [自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯 |
| | | * @param socket 网络套接字 |
| | | * @param headcode 头指令 |
| | | * @param customer 用户指令 |
| | | * @param send 发送的数据 |
| | | * @return 是否发送成功 |
| | | */ |
| | | protected OperateResult SendBaseAndCheckReceive(Socket socket, int headcode, int customer, byte[] send ) |
| | | { |
| | | // 数据处理 |
| | | send = HslProtocol.CommandBytes( headcode, customer, Token, send ); |
| | | |
| | | OperateResult sendResult = Send( socket, send ); |
| | | if(!sendResult.IsSuccess) return sendResult; |
| | | |
| | | // 检查对方接收完成 |
| | | OperateResultExOne<Long> checkResult = ReceiveLong( socket ); |
| | | if(!checkResult.IsSuccess) return checkResult; |
| | | |
| | | // 检查长度接收 |
| | | if (checkResult.Content != send.length) |
| | | { |
| | | CloseSocket(socket); |
| | | return new OperateResult(StringResources.Language.CommandLengthCheckFailed()); |
| | | } |
| | | |
| | | return checkResult; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * [自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯 |
| | | * @param socket 网络套接字 |
| | | * @param customer 用户指令 |
| | | * @param send 发送的数据 |
| | | * @return 是否发送成功 |
| | | */ |
| | | protected OperateResult SendBytesAndCheckReceive( Socket socket, int customer, byte[] send ) |
| | | { |
| | | return SendBaseAndCheckReceive( socket, HslProtocol.ProtocolUserBytes, customer, send ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * [自校验] 直接发送字符串数据并确认对方接收完成数据,如果结果异常,则结束通讯 |
| | | * @param socket 网络套接字 |
| | | * @param customer 用户指令 |
| | | * @param send 发送的数据 |
| | | * @return 是否发送成功 |
| | | */ |
| | | protected OperateResult SendStringAndCheckReceive( Socket socket, int customer, String send ) |
| | | { |
| | | byte[] data =(send == null || send.isEmpty() ) ? null : Utilities.string2Byte( send ); |
| | | |
| | | return SendBaseAndCheckReceive( socket, HslProtocol.ProtocolUserString, customer, data ); |
| | | } |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// [自校验] 将文件数据发送至套接字,如果结果异常,则结束通讯 |
| | | /// </summary> |
| | | /// <param name="socket">网络套接字</param> |
| | | /// <param name="filename">完整的文件路径</param> |
| | | /// <param name="filelength">文件的长度</param> |
| | | /// <param name="report">进度报告器</param> |
| | | /// <returns>是否发送成功</returns> |
| | | // protected OperateResult SendFileStreamToSocket( Socket socket, String filename, long filelength, BiConsumer<Long, Long> report ) |
| | | // { |
| | | // try |
| | | // { |
| | | // OperateResult result = null; |
| | | // FileInputStream |
| | | // using (FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read )) |
| | | // { |
| | | // result = SendStream( socket, fs, filelength, report, true ); |
| | | // } |
| | | // return result; |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // socket?.Close( ); |
| | | // LogNet?.WriteException( ToString( ), ex ); |
| | | // return new OperateResult( ) |
| | | // { |
| | | // Message = ex.Message |
| | | // }; |
| | | // } |
| | | // } |
| | | |
| | | |
| | | /// <summary> |
| | | /// [自校验] 将文件数据发送至套接字,具体发送细节将在继承类中实现,如果结果异常,则结束通讯 |
| | | /// </summary> |
| | | /// <param name="socket">套接字</param> |
| | | /// <param name="filename">文件名称,文件必须存在</param> |
| | | /// <param name="servername">远程端的文件名称</param> |
| | | /// <param name="filetag">文件的额外标签</param> |
| | | /// <param name="fileupload">文件的上传人</param> |
| | | /// <param name="sendReport">发送进度报告</param> |
| | | /// <returns>是否发送成功</returns> |
| | | // protected OperateResult SendFileAndCheckReceive( |
| | | // Socket socket, |
| | | // String filename, |
| | | // String servername, |
| | | // String filetag, |
| | | // String fileupload, |
| | | // BiConsumer<Long, Long> sendReport |
| | | // ) |
| | | // { |
| | | // // 发送文件名,大小,标签 |
| | | // File file = new File(filename); |
| | | // |
| | | // if (!file.exists()) |
| | | // { |
| | | // // 如果文件不存在 |
| | | // OperateResult stringResult = SendStringAndCheckReceive( socket, 0, "" ); |
| | | // if (!stringResult.IsSuccess) |
| | | // { |
| | | // return stringResult; |
| | | // } |
| | | // else |
| | | // { |
| | | // CloseSocket(socket); |
| | | // OperateResult result = new OperateResult(); |
| | | // result.Message = StringResources.FileNotExist; |
| | | // return result; |
| | | // } |
| | | // } |
| | | // |
| | | // // 文件存在的情况 |
| | | // Newtonsoft.Json.Linq.JObject json = new Newtonsoft.Json.Linq.JObject |
| | | // { |
| | | // { "FileName", new Newtonsoft.Json.Linq.JValue(servername) }, |
| | | // { "FileSize", new Newtonsoft.Json.Linq.JValue(file.length()) }, |
| | | // { "FileTag", new Newtonsoft.Json.Linq.JValue(filetag) }, |
| | | // { "FileUpload", new Newtonsoft.Json.Linq.JValue(fileupload) } |
| | | // }; |
| | | // |
| | | // // 先发送文件的信息到对方 |
| | | // OperateResult sendResult = SendStringAndCheckReceive( socket, 1, json.ToString( ) ); |
| | | // if (!sendResult.IsSuccess) |
| | | // { |
| | | // return sendResult; |
| | | // } |
| | | // |
| | | // // 最后发送 |
| | | // return SendFileStreamToSocket( socket, filename, file.length(), sendReport ); |
| | | // } |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// [自校验] 将流数据发送至套接字,具体发送细节将在继承类中实现,如果结果异常,则结束通讯 |
| | | /// </summary> |
| | | /// <param name="socket">套接字</param> |
| | | /// <param name="stream">文件名称,文件必须存在</param> |
| | | /// <param name="servername">远程端的文件名称</param> |
| | | /// <param name="filetag">文件的额外标签</param> |
| | | /// <param name="fileupload">文件的上传人</param> |
| | | /// <param name="sendReport">发送进度报告</param> |
| | | /// <returns></returns> |
| | | // protected OperateResult SendFileAndCheckReceive( |
| | | // Socket socket, |
| | | // Stream stream, |
| | | // String servername, |
| | | // String filetag, |
| | | // String fileupload, |
| | | // BiConsumer<Long, Long> sendReport |
| | | // ) |
| | | // { |
| | | // // 文件存在的情况 |
| | | // Newtonsoft.Json.Linq.JObject json = new Newtonsoft.Json.Linq.JObject |
| | | // { |
| | | // { "FileName", new Newtonsoft.Json.Linq.JValue(servername) }, |
| | | // { "FileSize", new Newtonsoft.Json.Linq.JValue(stream.Length) }, |
| | | // { "FileTag", new Newtonsoft.Json.Linq.JValue(filetag) }, |
| | | // { "FileUpload", new Newtonsoft.Json.Linq.JValue(fileupload) } |
| | | // }; |
| | | // |
| | | // |
| | | // // 发送文件信息 |
| | | // OperateResult fileResult = SendStringAndCheckReceive( socket, 1, json.ToString( ) ); |
| | | // if (!fileResult.IsSuccess) return fileResult; |
| | | // |
| | | // |
| | | // return SendStream( socket, stream, stream.count(), sendReport, true ); |
| | | // } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * [自校验] 接收一条完整的同步数据,包含头子节和内容字节,基础的数据,如果结果异常,则结束通讯 |
| | | * @param socket 套接字 |
| | | * @param timeout 超时时间设置,如果为负数,则不检查超时 |
| | | * @return 接收的结果数据 |
| | | */ |
| | | protected OperateResultExTwo<byte[], byte[]> ReceiveAndCheckBytes( Socket socket, int timeout ) { |
| | | // 30秒超时接收验证 |
| | | HslTimeOut hslTimeOut = new HslTimeOut(); |
| | | hslTimeOut.DelayTime = timeout; |
| | | hslTimeOut.IsSuccessful = false; |
| | | hslTimeOut.StartTime = new Date(); |
| | | hslTimeOut.WorkSocket = socket; |
| | | |
| | | |
| | | //if (timeout > 0) ThreadPool.QueueUserWorkItem( new WaitCallback( ThreadPoolCheckTimeOut ), hslTimeOut ); |
| | | |
| | | // 接收头指令 |
| | | OperateResultExOne<byte[]> headResult = Receive(socket, HslProtocol.HeadByteLength, timeout); |
| | | if (!headResult.IsSuccess) { |
| | | hslTimeOut.IsSuccessful = true; |
| | | return OperateResultExTwo.<byte[],byte[]>CreateFailedResult(headResult); |
| | | } |
| | | hslTimeOut.IsSuccessful = true; |
| | | |
| | | // 检查令牌 |
| | | if (!CheckRemoteToken(headResult.Content)) { |
| | | CloseSocket(socket); |
| | | return new OperateResultExTwo<>(StringResources.Language.TokenCheckFailed()); |
| | | } |
| | | |
| | | int contentLength = Utilities.getInt(headResult.Content, HslProtocol.HeadByteLength - 4); |
| | | // 接收内容 |
| | | OperateResultExOne<byte[]> contentResult = Receive(socket, contentLength); |
| | | if (!contentResult.IsSuccess) return OperateResultExTwo.CreateFailedResult(contentResult); |
| | | |
| | | // 返回成功信息 |
| | | OperateResult checkResult = SendLong(socket, HslProtocol.HeadByteLength + contentLength); |
| | | if (!checkResult.IsSuccess) return OperateResultExTwo.CreateFailedResult(checkResult); |
| | | |
| | | byte[] head = headResult.Content; |
| | | byte[] content = contentResult.Content; |
| | | content = HslProtocol.CommandAnalysis(head, content); |
| | | return OperateResultExTwo.CreateSuccessResult(head, content); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * [自校验] 从网络中接收一个字符串数据,如果结果异常,则结束通讯 |
| | | * @param socket 套接字 |
| | | * @return 接收的结果数据 |
| | | */ |
| | | protected OperateResultExTwo<Integer, String> ReceiveStringContentFromSocket( Socket socket ) { |
| | | OperateResultExTwo<byte[], byte[]> receive = ReceiveAndCheckBytes(socket, 10000); |
| | | if (!receive.IsSuccess) return OperateResultExTwo.CreateFailedResult(receive); |
| | | |
| | | // 检查是否是字符串信息 |
| | | if (Utilities.getInt(receive.Content1, 0) != HslProtocol.ProtocolUserString) { |
| | | if (LogNet != null) LogNet.WriteError(toString(), StringResources.Language.CommandHeadCodeCheckFailed()); |
| | | CloseSocket(socket); |
| | | return new OperateResultExTwo<>(StringResources.Language.CommandHeadCodeCheckFailed()); |
| | | } |
| | | |
| | | if (receive.Content2 == null) receive.Content2 = new byte[0]; |
| | | // 分析数据 |
| | | return OperateResultExTwo.CreateSuccessResult(Utilities.getInt(receive.Content1, 4), Utilities.byte2String(receive.Content2)); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * [自校验] 从网络中接收一串字节数据,如果结果异常,则结束通讯 |
| | | * @param socket 套接字 |
| | | * @return 结果数据对象 |
| | | */ |
| | | protected OperateResultExTwo<Integer, byte[]> ReceiveBytesContentFromSocket( Socket socket ) |
| | | { |
| | | OperateResultExTwo<byte[], byte[]> receive = ReceiveAndCheckBytes( socket, 10000 ); |
| | | if (!receive.IsSuccess) return OperateResultExTwo.CreateFailedResult(receive); |
| | | |
| | | // 检查是否是字节信息 |
| | | if (Utilities.getInt( receive.Content1, 0 ) != HslProtocol.ProtocolUserBytes) |
| | | { |
| | | if(LogNet!=null) LogNet.WriteError( toString( ), StringResources.Language.CommandHeadCodeCheckFailed() ); |
| | | CloseSocket(socket); |
| | | |
| | | return new OperateResultExTwo<>(StringResources.Language.CommandHeadCodeCheckFailed()); |
| | | } |
| | | |
| | | // 分析数据 |
| | | return OperateResultExTwo.CreateSuccessResult( Utilities.getInt( receive.Content1, 4 ), receive.Content2 ); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// [自校验] 从套接字中接收文件头信息 |
| | | /// </summary> |
| | | /// <param name="socket"></param> |
| | | /// <returns></returns> |
| | | // protected OperateResult<FileBaseInfo> ReceiveFileHeadFromSocket( Socket socket ) |
| | | // { |
| | | // // 先接收文件头信息 |
| | | // OperateResult<int, string> receiveString = ReceiveStringContentFromSocket( socket ); |
| | | // if (!receiveString.IsSuccess) return OperateResult.CreateFailedResult<FileBaseInfo>( receiveString ); |
| | | // |
| | | // // 判断文件是否存在 |
| | | // if (receiveString.Content1 == 0) |
| | | // { |
| | | // socket?.Close( ); |
| | | // LogNet?.WriteWarn( ToString( ), "对方文件不存在,无法接收!" ); |
| | | // return new OperateResult<FileBaseInfo>( ) |
| | | // { |
| | | // Message = StringResources.FileNotExist |
| | | // }; |
| | | // } |
| | | // |
| | | // OperateResult<FileBaseInfo> result = new OperateResult<FileBaseInfo>( ); |
| | | // result.Content = new FileBaseInfo( ); |
| | | // try |
| | | // { |
| | | // // 提取信息 |
| | | // Newtonsoft.Json.Linq.JObject json = Newtonsoft.Json.Linq.JObject.Parse( receiveString.Content2 ); |
| | | // result.Content.Name = SoftBasic.GetValueFromJsonObject( json, "FileName", "" ); |
| | | // result.Content.Size = SoftBasic.GetValueFromJsonObject( json, "FileSize", 0L ); |
| | | // result.Content.Tag = SoftBasic.GetValueFromJsonObject( json, "FileTag", "" ); |
| | | // result.Content.Upload = SoftBasic.GetValueFromJsonObject( json, "FileUpload", "" ); |
| | | // result.IsSuccess = true; |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // socket?.Close( ); |
| | | // result.Message = "提取信息失败," + ex.Message; |
| | | // } |
| | | // |
| | | // return result; |
| | | // } |
| | | |
| | | /// <summary> |
| | | /// [自校验] 从网络中接收一个文件,如果结果异常,则结束通讯 |
| | | /// </summary> |
| | | /// <param name="socket">网络套接字</param> |
| | | /// <param name="savename">接收文件后保存的文件名</param> |
| | | /// <param name="receiveReport">接收进度报告</param> |
| | | /// <returns></returns> |
| | | // protected OperateResult<FileBaseInfo> ReceiveFileFromSocket( Socket socket, string savename, Action<long, long> receiveReport ) |
| | | // { |
| | | // // 先接收文件头信息 |
| | | // OperateResult<FileBaseInfo> fileResult = ReceiveFileHeadFromSocket( socket ); |
| | | // if (!fileResult.IsSuccess) return fileResult; |
| | | // |
| | | // try |
| | | // { |
| | | // using (FileStream fs = new FileStream( savename, FileMode.Create, FileAccess.Write )) |
| | | // { |
| | | // WriteStream( socket, fs, fileResult.Content.Size, receiveReport, true ); |
| | | // } |
| | | // return fileResult; |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // LogNet?.WriteException( ToString( ), ex ); |
| | | // socket?.Close( ); |
| | | // return new OperateResult<FileBaseInfo>( ) |
| | | // { |
| | | // Message = ex.Message |
| | | // }; |
| | | // } |
| | | // } |
| | | |
| | | |
| | | /// <summary> |
| | | /// [自校验] 从网络中接收一个文件,写入数据流,如果结果异常,则结束通讯,参数顺序文件名,文件大小,文件标识,上传人 |
| | | /// </summary> |
| | | /// <param name="socket">网络套接字</param> |
| | | /// <param name="stream">等待写入的数据流</param> |
| | | /// <param name="receiveReport">接收进度报告</param> |
| | | /// <returns></returns> |
| | | // protected OperateResult<FileBaseInfo> ReceiveFileFromSocket( Socket socket, Stream stream, Action<long, long> receiveReport ) |
| | | // { |
| | | // // 先接收文件头信息 |
| | | // OperateResult<FileBaseInfo> fileResult = ReceiveFileHeadFromSocket( socket ); |
| | | // if (!fileResult.IsSuccess) return fileResult; |
| | | // |
| | | // try |
| | | // { |
| | | // WriteStream( socket, stream, fileResult.Content.Size, receiveReport, true ); |
| | | // return fileResult; |
| | | // } |
| | | // catch (Exception ex) |
| | | // { |
| | | // LogNet?.WriteException( ToString( ), ex ); |
| | | // socket?.Close( ); |
| | | // return new OperateResult<FileBaseInfo>( ) |
| | | // { |
| | | // Message = ex.Message |
| | | // }; |
| | | // } |
| | | // } |
| | | |
| | | |
| | | /** |
| | | * 删除文件的操作 |
| | | * @param filename 文件的名称 |
| | | * @return 是否删除成功 |
| | | */ |
| | | protected boolean DeleteFileByName( String filename ) |
| | | { |
| | | try |
| | | { |
| | | File file = new File(filename); |
| | | |
| | | if (!file.exists()) return true; |
| | | file.delete(); |
| | | return true; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | if(LogNet!=null) LogNet.WriteException( toString( ), "delete file failed:" + filename, ex ); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 预处理文件夹的名称,除去文件夹名称最后一个'\',如果有的话 |
| | | * @param folder 文件夹名称 |
| | | * @return 结果数据 |
| | | */ |
| | | protected String PreprocessFolderName( String folder ) { |
| | | if (folder.endsWith("\\")) { |
| | | return folder.substring(0, folder.length() - 1); |
| | | } else { |
| | | return folder; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从网络中接收Long数据 |
| | | * @param socket 套接字信息 |
| | | * @return 返回的结果 |
| | | */ |
| | | private OperateResultExOne<Long> ReceiveLong( Socket socket ) { |
| | | OperateResultExOne<byte[]> read = Receive(socket, 8); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(Utilities.getLong(read.Content, 0)); |
| | | } |
| | | |
| | | /** |
| | | * 将Long数据发送到套接字 |
| | | * @param socket 套接字 |
| | | * @param value 值 |
| | | * @return 返回的结果 |
| | | */ |
| | | private OperateResult SendLong( Socket socket, long value ) |
| | | { |
| | | return Send( socket, Utilities.getBytes( value ) ); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 发送一个流的所有数据到网络套接字 |
| | | * @param socket 网络套接字 |
| | | * @param stream 输入流 |
| | | * @param receive 接收长度 |
| | | * @param report 进度报告 |
| | | * @param reportByPercent 是否按照百分比报告进度 |
| | | * @return 是否成功 |
| | | */ |
| | | protected OperateResult SendStream(Socket socket, InputStream stream, long receive, ActionOperateExTwo<Long, Long> report, boolean reportByPercent ) |
| | | { |
| | | byte[] buffer = new byte[102400]; // 100K的数据缓存池 |
| | | long SendTotal = 0; |
| | | long percent = 0; |
| | | while (SendTotal < receive) |
| | | { |
| | | // 先从流中接收数据 |
| | | OperateResultExOne<Integer> read = ReadStream( stream, buffer ); |
| | | if (!read.IsSuccess) |
| | | { |
| | | OperateResult result = new OperateResult(); |
| | | result.Message = read.Message; |
| | | return result; |
| | | } |
| | | else |
| | | { |
| | | SendTotal += read.Content; |
| | | } |
| | | |
| | | // 然后再异步写到socket中 |
| | | byte[] newBuffer = new byte[read.Content]; |
| | | System.arraycopy( buffer, 0, newBuffer, 0, newBuffer.length ); |
| | | OperateResult write = SendBytesAndCheckReceive( socket, read.Content, newBuffer ); |
| | | if (!write.IsSuccess) |
| | | { |
| | | OperateResult result = new OperateResult(); |
| | | result.Message = write.Message; |
| | | return result; |
| | | } |
| | | |
| | | // 报告进度 |
| | | if (reportByPercent) |
| | | { |
| | | long percentCurrent = SendTotal * 100 / receive; |
| | | if (percent != percentCurrent) |
| | | { |
| | | percent = percentCurrent; |
| | | if(report!=null) report.Action( SendTotal, receive ); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 报告进度 |
| | | if(report!=null) report.Action( SendTotal, receive ); |
| | | } |
| | | } |
| | | |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从套接字中接收所有的数据然后写入到流当中去 |
| | | * @param socket 网络套接字 |
| | | * @param stream 输出流 |
| | | * @param totalLength 总长度 |
| | | * @param report 进度报告 |
| | | * @param reportByPercent 进度报告是否按照百分比 |
| | | * @return 结果类对象 |
| | | */ |
| | | protected OperateResult WriteStream(Socket socket, OutputStream stream, long totalLength, ActionOperateExTwo<Long, Long> report, boolean reportByPercent ) |
| | | { |
| | | long count_receive = 0; |
| | | long percent = 0; |
| | | while (count_receive < totalLength) |
| | | { |
| | | // 先从流中异步接收数据 |
| | | OperateResultExTwo<Integer,byte[]> read = ReceiveBytesContentFromSocket( socket ); |
| | | if (!read.IsSuccess) |
| | | { |
| | | OperateResult result = new OperateResult(); |
| | | result.Message = read.Message; |
| | | return result; |
| | | } |
| | | count_receive += read.Content1; |
| | | |
| | | // 开始写入文件流 |
| | | OperateResult write = WriteStream( stream, read.Content2 ); |
| | | if (!write.IsSuccess) |
| | | { |
| | | OperateResult result = new OperateResult(); |
| | | result.Message = write.Message; |
| | | return result; |
| | | } |
| | | |
| | | // 报告进度 |
| | | if (reportByPercent) |
| | | { |
| | | long percentCurrent = count_receive * 100 / totalLength; |
| | | if (percent != percentCurrent) |
| | | { |
| | | percent = percentCurrent; |
| | | if(report!=null) report.Action( count_receive, totalLength ); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if(report!=null) report.Action( count_receive, totalLength ); |
| | | } |
| | | |
| | | } |
| | | |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return "NetworkXBase"; |
| | | } |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/net/session/AlienSession.java |
| | |
| | | package com.zy.gateway.core.net.session; |
| | | package com.zy.common.HslCommunication.Core.Net.StateOne; |
| | | |
| | | import java.net.Socket; |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/net/session/AppSession.java |
| | |
| | | package com.zy.gateway.core.net.session; |
| | | package com.zy.common.HslCommunication.Core.Net.StateOne; |
| | | |
| | | import com.zy.gateway.core.base.SoftBasic; |
| | | import com.zy.gateway.core.net.HslProtocol; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.Net.HslProtocol; |
| | | |
| | | import java.net.InetAddress; |
| | | import java.net.Socket; |
File was renamed from src/main/java/com/zy/gateway/core/base/HslSecurity.java |
| | |
| | | package com.zy.gateway.core.base; |
| | | package com.zy.common.HslCommunication.Core.Security; |
| | | |
| | | public class HslSecurity { |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/transfer/ByteTransformBase.java |
| | |
| | | package com.zy.gateway.core.transfer; |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | |
| | | /** |
File was renamed from src/main/java/com/zy/gateway/core/transfer/ByteTransformHelper.java |
| | |
| | | package com.zy.gateway.core.transfer; |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | import com.zy.gateway.core.base.SoftBasic; |
| | | import com.zy.gateway.core.domain.FunctionOperateExOne; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.Types.FunctionOperateExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | |
| | | public class ByteTransformHelper { |
| | | |
| | |
| | | * @param <TResult> 结果类型 |
| | | * @return 最新的结果对象 |
| | | */ |
| | | public static <TResult> OperateResultExOne<TResult> GetResultFromBytes(OperateResultExOne<byte[]> result, FunctionOperateExOne<byte[], TResult> translator ) |
| | | public static <TResult> OperateResultExOne<TResult> GetResultFromBytes( OperateResultExOne<byte[]> result, FunctionOperateExOne<byte[], TResult> translator ) |
| | | { |
| | | OperateResultExOne<TResult> tmp = new OperateResultExOne<TResult>( ); |
| | | try |
File was renamed from src/main/java/com/zy/gateway/core/transfer/DataFormat.java |
| | |
| | | package com.zy.gateway.core.transfer; |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | /** |
| | | * 应用于多字节数据的解析或是生成格式 |
File was renamed from src/main/java/com/zy/gateway/core/transfer/IByteTransform.java |
| | |
| | | package com.zy.gateway.core.transfer; |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | public interface IByteTransform { |
| | | |
| | |
| | | * @param index 索引位置 |
| | | * @return boolean值 |
| | | */ |
| | | boolean TransBool(byte[] buffer, int index); |
| | | boolean TransBool( byte[] buffer, int index ); |
| | | |
| | | /** |
| | | * 缓存中提取byte结果 |
| | |
| | | * @param index 索引位置 |
| | | * @return byte对象 |
| | | */ |
| | | byte TransByte(byte[] buffer, int index); |
| | | byte TransByte( byte[] buffer, int index ); |
| | | |
| | | /** |
| | | * 从缓存中提取byte数组结果 |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return |
| | | */ |
| | | byte[] TransByte(byte[] buffer, int index, int length); |
| | | byte[] TransByte( byte[] buffer, int index, int length ); |
| | | |
| | | /** |
| | | * 从缓存中提取short结果 |
| | |
| | | * @param index 索引位置 |
| | | * @return short对象 |
| | | */ |
| | | short TransInt16(byte[] buffer, int index); |
| | | short TransInt16( byte[] buffer, int index ); |
| | | |
| | | /** |
| | | * 从缓存中提取short结果 |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return short数组对象 |
| | | */ |
| | | short[] TransInt16(byte[] buffer, int index, int length); |
| | | short[] TransInt16( byte[] buffer, int index, int length ); |
| | | |
| | | /** |
| | | * 从缓存中提取int结果 |
| | |
| | | * @param index 索引位置 |
| | | * @return int对象 |
| | | */ |
| | | int TransInt32(byte[] buffer, int index); |
| | | int TransInt32( byte[] buffer, int index ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return int数组对象 |
| | | */ |
| | | int[] TransInt32(byte[] buffer, int index, int length); |
| | | int[] TransInt32( byte[] buffer, int index, int length ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param index 索引位置 |
| | | * @return long对象 |
| | | */ |
| | | long TransInt64(byte[] buffer, int index); |
| | | long TransInt64( byte[] buffer, int index ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return long数组对象 |
| | | */ |
| | | long[] TransInt64(byte[] buffer, int index, int length); |
| | | long[] TransInt64( byte[] buffer, int index, int length ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param index 索引位置 |
| | | * @return float对象 |
| | | */ |
| | | float TransSingle(byte[] buffer, int index); |
| | | float TransSingle( byte[] buffer, int index ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return float数组对象 |
| | | */ |
| | | float[] TransSingle(byte[] buffer, int index, int length); |
| | | float[] TransSingle( byte[] buffer, int index, int length ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param index 索引位置 |
| | | * @return double对象 |
| | | */ |
| | | double TransDouble(byte[] buffer, int index); |
| | | double TransDouble( byte[] buffer, int index ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param length 读取的数组长度 |
| | | * @return double数组 |
| | | */ |
| | | double[] TransDouble(byte[] buffer, int index, int length); |
| | | double[] TransDouble( byte[] buffer, int index, int length ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param encoding 字符串的编码 |
| | | * @return string对象 |
| | | */ |
| | | String TransString(byte[] buffer, int index, int length, String encoding); |
| | | String TransString( byte[] buffer, int index, int length, String encoding ); |
| | | |
| | | |
| | | |
| | |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(boolean value); |
| | | byte[] TransByte( boolean value ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(boolean[] values); |
| | | byte[] TransByte( boolean[] values ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(byte value); |
| | | byte[] TransByte( byte value ); |
| | | |
| | | /** |
| | | * short变量转化缓存数据 |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(short value); |
| | | byte[] TransByte( short value ); |
| | | |
| | | /** |
| | | * short数组变量转化缓存数据 |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(short[] values); |
| | | byte[] TransByte( short[] values ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(int value); |
| | | byte[] TransByte( int value ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(int[] values); |
| | | byte[] TransByte( int[] values ); |
| | | |
| | | /** |
| | | * long变量转化缓存数据 |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(long value); |
| | | byte[] TransByte( long value ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param values 等待转化的数组 |
| | | * @return v |
| | | */ |
| | | byte[] TransByte(long[] values); |
| | | byte[] TransByte( long[] values ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(float value); |
| | | byte[] TransByte( float value ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(float[] values); |
| | | byte[] TransByte( float[] values ); |
| | | |
| | | |
| | | /** |
| | |
| | | * @param value 等待转化的数据 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(double value); |
| | | byte[] TransByte( double value ); |
| | | |
| | | /** |
| | | * double数组变量转化缓存数据 |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(double[] values); |
| | | byte[] TransByte( double[] values ); |
| | | |
| | | /** |
| | | * 使用指定的编码字符串转化缓存数据 |
| | |
| | | * @param encoding 字符串的编码方式 |
| | | * @return buffer数据 |
| | | */ |
| | | byte[] TransByte(String value, String encoding); |
| | | byte[] TransByte( String value, String encoding ); |
| | | |
| | | |
| | | /** |
| | | * 设置数据解析的格式,ABCD,BADC,CDAB,DCBA格式 |
| | | * @param dataFormat |
| | | */ |
| | | void setDataFormat(DataFormat dataFormat); |
| | | void setDataFormat( DataFormat dataFormat ); |
| | | |
| | | /** |
| | | * 获取数据解析的格式,默认ABCD,可选BADC,CDAB,DCBA格式 |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | public class RegularByteTransform extends ByteTransformBase |
| | | { |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/transfer/ReverseBytesTransform.java |
| | |
| | | package com.zy.gateway.core.transfer; |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * 反转的字节变换类 |
New file |
| | |
| | | package com.zy.common.HslCommunication.Core.Transfer; |
| | | |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * 以字节为单位的变换操作 |
| | | */ |
| | | public class ReverseWordTransform extends ByteTransformBase |
| | | { |
| | | /** |
| | | * 实例化一个默认的对象 |
| | | */ |
| | | public ReverseWordTransform(){ |
| | | this.setDataFormat(DataFormat.ABCD); |
| | | } |
| | | |
| | | /** |
| | | * 按照字节错位的方法 |
| | | * @param buffer 实际的字节数据 |
| | | * @param index 起始字节位置 |
| | | * @param length 数据长度 |
| | | * @return |
| | | */ |
| | | private byte[] ReverseBytesByWord( byte[] buffer, int index, int length ) |
| | | { |
| | | byte[] tmp = new byte[length]; |
| | | |
| | | for (int i = 0; i < length; i++) |
| | | { |
| | | tmp[i] = buffer[index + i]; |
| | | } |
| | | |
| | | for (int i = 0; i < length / 2; i++) |
| | | { |
| | | byte b = tmp[i * 2 + 0]; |
| | | tmp[i * 2 + 0] = tmp[i * 2 + 1]; |
| | | tmp[i * 2 + 1] = b; |
| | | } |
| | | |
| | | return tmp; |
| | | } |
| | | |
| | | private byte[] ReverseBytesByWord( byte[] buffer ) |
| | | { |
| | | return ReverseBytesByWord( buffer, 0, buffer.length ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 字符串数据是否按照字来反转 |
| | | */ |
| | | public boolean IsStringReverse =false; |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从缓存中提取short结果 |
| | | * @param buffer 缓存数据 |
| | | * @param index 索引位置 |
| | | * @return short对象 |
| | | */ |
| | | @Override |
| | | public short TransInt16( byte[] buffer, int index ) { |
| | | return Utilities.getShort(ReverseBytesByWord(buffer, index, 2), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从缓存中提取string结果,使用指定的编码 |
| | | * @param buffer 缓存对象 |
| | | * @param index 索引位置 |
| | | * @param length byte数组长度 |
| | | * @param encoding 字符串的编码 |
| | | * @return string对象 |
| | | */ |
| | | @Override |
| | | public String TransString( byte[] buffer, int index, int length, String encoding ) { |
| | | byte[] tmp = TransByte(buffer, index, length); |
| | | |
| | | if (IsStringReverse) { |
| | | return Utilities.getString(ReverseBytesByWord(tmp), "ASCII"); |
| | | } else { |
| | | return Utilities.getString(tmp, "ASCII"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * bool数组变量转化缓存数据 |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | @Override |
| | | public byte[] TransByte( boolean[] values ) { |
| | | return SoftBasic.BoolArrayToByte(values); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * short数组变量转化缓存数据 |
| | | * @param values 等待转化的数组 |
| | | * @return buffer数据 |
| | | */ |
| | | @Override |
| | | public byte[] TransByte( short[] values ) { |
| | | if (values == null) return null; |
| | | |
| | | byte[] buffer = new byte[values.length * 2]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | byte[] tmp = Utilities.getBytes(values[i]); |
| | | System.arraycopy(tmp, 0, buffer, 2 * i, tmp.length); |
| | | } |
| | | |
| | | return ReverseBytesByWord(buffer); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 使用指定的编码字符串转化缓存数据 |
| | | * @param value 等待转化的数据 |
| | | * @param encoding 字符串的编码方式 |
| | | * @return buffer数据 |
| | | */ |
| | | @Override |
| | | public byte[] TransByte( String value, String encoding ) { |
| | | if (value == null) return null; |
| | | byte[] buffer = Utilities.getBytes(value, encoding); |
| | | buffer = SoftBasic.ArrayExpandToLengthEven(buffer); |
| | | if (IsStringReverse) { |
| | | return ReverseBytesByWord(buffer); |
| | | } else { |
| | | return buffer; |
| | | } |
| | | } |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/domain/ActionOperate.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 空操作的类 |
File was renamed from src/main/java/com/zy/gateway/core/domain/ActionOperateExOne.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 带一个参数对象的操作类 |
File was renamed from src/main/java/com/zy/gateway/core/domain/ActionOperateExThree.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 带三个参数的类型对象 |
File was renamed from src/main/java/com/zy/gateway/core/domain/ActionOperateExTwo.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 带二个参数对象的操作类 |
File was renamed from src/main/java/com/zy/gateway/core/domain/FunctionOperate.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | public class FunctionOperate<R> |
| | | { |
File was renamed from src/main/java/com/zy/gateway/core/domain/FunctionOperateExOne.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | public class FunctionOperateExOne<T,R> |
| | | { |
File was renamed from src/main/java/com/zy/gateway/core/domain/HslTimeOut.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | import java.net.Socket; |
| | | import java.util.Date; |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/domain/IDataTransfer.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 用于PLC通讯及Modbus自定义数据类型的读写操作 |
File was renamed from src/main/java/com/zy/gateway/core/domain/OperateResult.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | import com.zy.gateway.core.StringResources; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | |
| | | /** |
| | | * 一个结果操作类的基类 |
| | |
| | | * @param err 错误码 |
| | | * @param msg 错误消息 |
| | | */ |
| | | public OperateResult(int err, String msg){ |
| | | public OperateResult(int err,String msg){ |
| | | this.ErrorCode = err; |
| | | this.Message = msg; |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/domain/OperateResultExFour.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 带三个参数的泛型类对象 |
File was renamed from src/main/java/com/zy/gateway/core/domain/OperateResultExOne.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | |
| | | /** |
| | | * 带一个参数的结果类对象 |
| | | * @param <T> |
| | | */ |
| | | public class OperateResultExOne<T> extends OperateResult { |
| | | public class OperateResultExOne<T> extends OperateResult |
| | | { |
| | | |
| | | /** |
| | | * 默认的无参构造方法 |
| | |
| | | * @param err 错误码 |
| | | * @param msg 错误消息 |
| | | */ |
| | | public OperateResultExOne(int err, String msg){ |
| | | public OperateResultExOne(int err,String msg){ |
| | | super(err,msg); |
| | | } |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/domain/OperateResultExThree.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | |
| | | /** |
File was renamed from src/main/java/com/zy/gateway/core/domain/OperateResultExTwo.java |
| | |
| | | package com.zy.gateway.core.domain; |
| | | package com.zy.common.HslCommunication.Core.Types; |
| | | |
| | | /** |
| | | * 带2个参数的结果类 |
New file |
| | |
| | | package com.zy.common.HslCommunication.Enthernet.ComplexNet; |
| | | |
| | | import com.zy.common.HslCommunication.Core.Net.HslProtocol; |
| | | import com.zy.common.HslCommunication.Core.Net.NetHandle; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkXBase; |
| | | import com.zy.common.HslCommunication.Core.Net.StateOne.AppSession; |
| | | import com.zy.common.HslCommunication.Core.Types.*; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.net.Socket; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 一个基于异步高性能的客户端网络类,支持主动接收服务器的消息 |
| | | */ |
| | | public class NetComplexClient extends NetworkXBase { |
| | | |
| | | |
| | | /** |
| | | * 实例化一个对象 |
| | | */ |
| | | public NetComplexClient() { |
| | | session = new AppSession(); |
| | | ServerTime = new Date(); |
| | | |
| | | } |
| | | |
| | | |
| | | private AppSession session; // 客户端的核心连接对象 |
| | | private int isConnecting = 0; // 指示客户端是否处于连接服务器中,0代表未连接,1代表连接中 |
| | | private boolean IsQuie = false; // 指示系统是否准备退出 |
| | | private Thread thread_heart_check = null; // 心跳线程 |
| | | private String ipAddress = ""; // Ip地址 |
| | | private int port = 1000; // 端口号 |
| | | private boolean IsClientStart = false; // 客户端是否启动 |
| | | private int ConnectFailedCount = 0; // 失败重连次数 |
| | | private String ClientAlias = ""; // 客户端的别名 |
| | | private Date ServerTime = new Date(); // 服务器的时间,暂时不支持使用 |
| | | private int DelayTime = 0; // 获取延迟的时间 |
| | | |
| | | /** |
| | | * 获取IP地址 |
| | | * |
| | | * @return Ip地址 |
| | | */ |
| | | public String getIpAddress() { |
| | | return ipAddress; |
| | | } |
| | | |
| | | /** |
| | | * 设置Ip地址 |
| | | * |
| | | * @param ipAddress Ip地址 |
| | | */ |
| | | public void setIpAddress(String ipAddress) { |
| | | this.ipAddress = ipAddress; |
| | | } |
| | | |
| | | /** |
| | | * 获取端口号 |
| | | * |
| | | * @return 端口号 |
| | | */ |
| | | public int getPort() { |
| | | return port; |
| | | } |
| | | |
| | | /** |
| | | * 设置端口号 |
| | | * |
| | | * @param port |
| | | */ |
| | | public void setPort(int port) { |
| | | this.port = port; |
| | | } |
| | | |
| | | /** |
| | | * 获取客户端是否启动 |
| | | * |
| | | * @return boolean值 |
| | | */ |
| | | public boolean getIsClientStart() { |
| | | return IsClientStart; |
| | | } |
| | | |
| | | /** |
| | | * 设置客户端是否启动 |
| | | * |
| | | * @param clientStart 客户端是否启动 |
| | | */ |
| | | public void setClientStart(boolean clientStart) { |
| | | IsClientStart = clientStart; |
| | | } |
| | | |
| | | /** |
| | | * 获取失败重连次数 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getConnectFailedCount() { |
| | | return ConnectFailedCount; |
| | | } |
| | | |
| | | /** |
| | | * 获取客户端的登录标识名 |
| | | * |
| | | * @return 字符串信息 |
| | | */ |
| | | public String getClientAlias() { |
| | | return ClientAlias; |
| | | } |
| | | |
| | | /** |
| | | * 设置客户端的登录标识名 |
| | | * |
| | | * @param clientAlias |
| | | */ |
| | | public void setClientAlias(String clientAlias) { |
| | | ClientAlias = clientAlias; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取服务器的时间 |
| | | * @return |
| | | */ |
| | | // public Date getServerTime() { |
| | | // return ServerTime; |
| | | // } |
| | | |
| | | /** |
| | | * 获取信息延迟的时间 |
| | | * |
| | | * @return |
| | | */ |
| | | public int getDelayTime() { |
| | | return DelayTime; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 客户端启动成功的事件,重连成功也将触发此事件,参数没有意义 |
| | | */ |
| | | public ActionOperate LoginSuccess; |
| | | |
| | | /** |
| | | * 连接失败时触发的事件,参数为连接失败的次数 |
| | | */ |
| | | public ActionOperateExOne<Integer> LoginFailed; |
| | | |
| | | /** |
| | | * 服务器的异常,启动,等等一般消息产生的时候,出发此事件 |
| | | */ |
| | | public ActionOperateExOne<String> MessageAlerts; |
| | | |
| | | /** |
| | | * 在客户端断开后并在重连服务器之前触发,用于清理系统资源,参数无意义 |
| | | */ |
| | | public ActionOperate BeforReConnected; |
| | | |
| | | /** |
| | | * 当接收到文本数据的时候,触发此事件 |
| | | */ |
| | | public ActionOperateExThree<NetComplexClient, NetHandle, String> AcceptString; |
| | | |
| | | /** |
| | | * 当接收到字节数据的时候,触发此事件 |
| | | */ |
| | | public ActionOperateExThree<NetComplexClient, NetHandle, byte[]> AcceptByte; |
| | | |
| | | |
| | | /** |
| | | * 关闭该客户端引擎 |
| | | */ |
| | | public void ClientClose() { |
| | | IsQuie = true; |
| | | if (IsClientStart) |
| | | SendBytes(session, HslProtocol.CommandBytes(HslProtocol.ProtocolClientQuit, 0, Token, null)); |
| | | |
| | | IsClientStart = false; // 关闭客户端 |
| | | thread_heart_check = null; |
| | | |
| | | LoginSuccess = null; // 清空所有的事件 |
| | | LoginFailed = null; |
| | | MessageAlerts = null; |
| | | AcceptByte = null; |
| | | AcceptString = null; |
| | | try { |
| | | session.getWorkSocket().close(); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | if (LogNet != null) LogNet.WriteDebug(toString(), "Client Close."); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 启动客户端引擎,连接服务器系统 |
| | | */ |
| | | public void ClientStart() { |
| | | // 如果处于连接中就退出 |
| | | if (isConnecting != 0) return; |
| | | isConnecting = 1; |
| | | |
| | | // 启动后台线程连接 |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | ThreadLogin(); |
| | | } |
| | | }.start(); |
| | | |
| | | // 启动心跳线程,在第一次Start的时候 |
| | | if (thread_heart_check == null) { |
| | | thread_heart_check = new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | ThreadHeartCheck(); |
| | | } |
| | | }; |
| | | thread_heart_check.start(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 连接服务器之前的消息提示,如果是重连的话,就提示10秒等待信息 |
| | | */ |
| | | private void AwaitToConnect() { |
| | | if (ConnectFailedCount == 0) { |
| | | // English Version : Connecting Server... |
| | | if (MessageAlerts != null) MessageAlerts.Action("正在连接服务器..."); |
| | | } else { |
| | | int count = 10; |
| | | while (count > 0) { |
| | | if (IsQuie) return; |
| | | count--; |
| | | // English Version : Disconnected, wait [count] second to restart |
| | | if (MessageAlerts != null) MessageAlerts.Action("连接断开,等待" + count + "秒后重新连接"); |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | } |
| | | if (MessageAlerts != null) MessageAlerts.Action("正在尝试第" + ConnectFailedCount + "次连接服务器..."); |
| | | } |
| | | } |
| | | |
| | | private void ConnectFailed() { |
| | | ConnectFailedCount++; |
| | | isConnecting = 0; |
| | | if (LoginFailed != null) LoginFailed.Action(ConnectFailedCount); |
| | | if (LogNet != null) LogNet.WriteDebug(toString(), "Connected Failed, Times: " + ConnectFailedCount); |
| | | } |
| | | |
| | | private OperateResultExOne<Socket> ConnectServer() { |
| | | OperateResultExOne<Socket> connectResult = CreateSocketAndConnect(ipAddress, port, 10000); |
| | | if (!connectResult.IsSuccess) { |
| | | return connectResult; |
| | | } |
| | | |
| | | // 连接成功,发送数据信息 |
| | | OperateResult sendResult = SendStringAndCheckReceive(connectResult.Content, 2, ClientAlias); |
| | | if (!sendResult.IsSuccess) { |
| | | return OperateResultExOne.<Socket>CreateFailedResult(sendResult); |
| | | } |
| | | |
| | | if (MessageAlerts != null) MessageAlerts.Action("连接服务器成功!"); |
| | | return connectResult; |
| | | } |
| | | |
| | | private void LoginSuccessMethod(Socket socket) { |
| | | ConnectFailedCount = 0; |
| | | try { |
| | | session.setIpEndPoint(socket.getInetAddress()); |
| | | session.setLoginAlias(ClientAlias); |
| | | session.setWorkSocket(socket); |
| | | session.setHeartTime(new Date()); |
| | | IsClientStart = true; |
| | | BeginReceiveBackground(session); |
| | | } catch (Exception ex) { |
| | | if (LogNet != null) LogNet.WriteException(toString(), ex); |
| | | } |
| | | } |
| | | |
| | | |
| | | private void ThreadLogin() { |
| | | // 连接的消息等待 |
| | | AwaitToConnect(); |
| | | |
| | | OperateResultExOne<Socket> connectResult = ConnectServer(); |
| | | if (!connectResult.IsSuccess) { |
| | | ConnectFailed(); |
| | | // 连接失败,重新连接服务器 |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | ReconnectServer(null); |
| | | } |
| | | }.start(); |
| | | return; |
| | | } |
| | | |
| | | // 登录成功 |
| | | LoginSuccessMethod(connectResult.Content); |
| | | |
| | | // 登录成功 |
| | | if (LoginSuccess != null) LoginSuccess.Action(); |
| | | isConnecting = 0; |
| | | try { |
| | | Thread.sleep(200); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | private void ReconnectServer(Object obj) { |
| | | // 是否连接服务器中,已经在连接的话,则不再连接 |
| | | if (isConnecting == 1) return; |
| | | // 是否退出了系统,退出则不再重连 |
| | | if (IsQuie) return; |
| | | // 触发连接失败,重连系统前错误 |
| | | if (BeforReConnected != null) BeforReConnected.Action(); |
| | | if (session != null) { |
| | | CloseSocket(session.getWorkSocket()); |
| | | } |
| | | // 重新启动客户端 |
| | | ClientStart(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 通信出错后的处理 |
| | | * |
| | | * @param receive 通信方法 |
| | | */ |
| | | @Override |
| | | protected void SocketReceiveException(AppSession receive) { |
| | | if (LogNet != null) LogNet.WriteDebug(toString(), "Socket Excepiton Occured."); |
| | | // 异常掉线 |
| | | ReconnectServer(null); |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 服务器端用于数据发送文本的方法 |
| | | * |
| | | * @param customer 用户自定义的命令头 |
| | | * @param str 发送的文本 |
| | | */ |
| | | public void Send(NetHandle customer, String str) { |
| | | if (IsClientStart) { |
| | | SendBytes(session, HslProtocol.CommandBytes(customer.get_CodeValue(), Token, str)); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 服务器端用于发送字节的方法 |
| | | * |
| | | * @param customer 用户自定义的命令头 |
| | | * @param bytes 实际发送的数据 |
| | | */ |
| | | public void Send(NetHandle customer, byte[] bytes) { |
| | | if (IsClientStart) { |
| | | SendBytes(session, HslProtocol.CommandBytes(customer.get_CodeValue(), Token, bytes)); |
| | | } |
| | | } |
| | | |
| | | private void SendBytes(AppSession stateone, byte[] content) { |
| | | super.Send(stateone.getWorkSocket(), content); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 客户端的数据处理中心 |
| | | * |
| | | * @param session 连接状态 |
| | | * @param protocol 协议头 |
| | | * @param customer 用户自定义 |
| | | * @param content 数据内容 |
| | | */ |
| | | @Override |
| | | protected void DataProcessingCenter(AppSession session, int protocol, int customer, byte[] content) { |
| | | if (protocol == HslProtocol.ProtocolCheckSecends) { |
| | | Date dt = new Date(Utilities.getLong(content, 0)); |
| | | ServerTime = new Date(Utilities.getLong(content, 8)); |
| | | DelayTime = (int) (new Date().getTime() - dt.getTime()); |
| | | this.session.setHeartTime(new Date()); |
| | | // MessageAlerts?.Invoke("心跳时间:" + DateTime.Now.ToString()); |
| | | } else if (protocol == HslProtocol.ProtocolClientQuit) { |
| | | // 申请了退出 |
| | | } else if (protocol == HslProtocol.ProtocolUserBytes) { |
| | | // 接收到字节数据 |
| | | if (AcceptByte != null) AcceptByte.Action(this, new NetHandle(customer), content); |
| | | } else if (protocol == HslProtocol.ProtocolUserString) { |
| | | // 接收到文本数据 |
| | | String str = Utilities.byte2String(content); |
| | | if (AcceptString != null) AcceptString.Action(this, new NetHandle(customer), str); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 心跳线程的方法 |
| | | */ |
| | | private void ThreadHeartCheck() { |
| | | try { |
| | | Thread.sleep(2000); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | while (true) { |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | |
| | | if (!IsQuie) { |
| | | byte[] send = new byte[16]; |
| | | byte[] buffer = Utilities.getBytes(new Date().getTime()); |
| | | System.arraycopy(buffer, 0, send, 0, buffer.length); |
| | | |
| | | try { |
| | | SendBytes(session, HslProtocol.CommandBytes(HslProtocol.ProtocolCheckSecends, 0, Token, send)); |
| | | double timeSpan = (new Date().getTime() - session.getHeartTime().getTime()) / 1000; |
| | | if (timeSpan > 1 * 8)//8次没有收到失去联系 |
| | | { |
| | | if (isConnecting == 0) { |
| | | if (LogNet != null) |
| | | LogNet.WriteDebug(toString(), "Heart Check Failed int " + timeSpan + " Seconds."); |
| | | new Thread(){ |
| | | @Override |
| | | public void run() { |
| | | ReconnectServer(null); |
| | | } |
| | | }.start(); |
| | | } |
| | | if (!IsQuie) { |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | } catch (Exception ex) { |
| | | System.out.println(ex.getStackTrace()); |
| | | } |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 返回对象的字符串表示形式 |
| | | * |
| | | * @return 字符串 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "NetComplexClient"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Enthernet.FileNet; |
| | | |
| | | public class FileBaseInfo { |
| | | |
| | | /** |
| | | * 获取文件的名称 |
| | | * @return |
| | | */ |
| | | public String getName() { |
| | | return Name; |
| | | } |
| | | |
| | | /** |
| | | * 设置文件的名称 |
| | | * @param name |
| | | */ |
| | | public void setName(String name) { |
| | | Name = name; |
| | | } |
| | | |
| | | /** |
| | | * 获取文件的大小 |
| | | * @return |
| | | */ |
| | | public long getSize() { |
| | | return Size; |
| | | } |
| | | |
| | | /** |
| | | * 设置文件的大小 |
| | | * @param size |
| | | */ |
| | | public void setSize(long size) { |
| | | Size = size; |
| | | } |
| | | |
| | | /** |
| | | * 获取文件的标识,注释 |
| | | * @return |
| | | */ |
| | | public String getTag() { |
| | | return Tag; |
| | | } |
| | | |
| | | /** |
| | | * 设置文件的标识,注释 |
| | | * @param tag |
| | | */ |
| | | public void setTag(String tag) { |
| | | Tag = tag; |
| | | } |
| | | |
| | | /** |
| | | * 获取文件的上传人 |
| | | * @return |
| | | */ |
| | | public String getUpload() { |
| | | return Upload; |
| | | } |
| | | |
| | | /** |
| | | * 设置文件的上传人 |
| | | * @param upload |
| | | */ |
| | | public void setUpload(String upload) { |
| | | Upload = upload; |
| | | } |
| | | |
| | | private String Name ; // 文件名称 |
| | | private long Size; // 文件大小 |
| | | private String Tag; // 文件的标识,注释 |
| | | private String Upload; // 文件上传人 |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Enthernet.PushNet; |
| | | |
| | | import com.zy.common.HslCommunication.Core.Net.HslProtocol; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkXBase; |
| | | import com.zy.common.HslCommunication.Core.Net.StateOne.AppSession; |
| | | import com.zy.common.HslCommunication.Core.Types.ActionOperateExTwo; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.net.Socket; |
| | | |
| | | public class NetPushClient extends NetworkXBase |
| | | { |
| | | |
| | | /** |
| | | * 实例化一个发布订阅类的客户端,需要指定ip地址,端口,及订阅关键字 |
| | | * @param ipAddress 服务器的IP地址 |
| | | * @param port 服务器的端口号 |
| | | * @param key 订阅关键字 |
| | | */ |
| | | public NetPushClient( String ipAddress, int port, String key ) |
| | | { |
| | | this.ipAddress = ipAddress; |
| | | this.port = port; |
| | | keyWord = key; |
| | | |
| | | if (key == null || key.isEmpty()) |
| | | { |
| | | throw new RuntimeException( "key 不允许为空" ); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | protected void DataProcessingCenter(AppSession session, int protocol, int customer, byte[] content ) { |
| | | if (protocol == HslProtocol.ProtocolUserString) { |
| | | if (action != null) action.Action(this, Utilities.byte2String(content)); |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | protected void SocketReceiveException( AppSession session) { |
| | | // 发生异常的时候需要进行重新连接 |
| | | while (true) { |
| | | System.out.print("10 秒钟后尝试重连服务器"); |
| | | try { |
| | | Thread.sleep(10000); |
| | | }catch (Exception ex){ |
| | | |
| | | } |
| | | |
| | | if (CreatePush().IsSuccess) { |
| | | System.out.print("重连服务器成功"); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | private OperateResult CreatePush( ) |
| | | { |
| | | CloseSocket(CoreSocket); |
| | | |
| | | OperateResultExOne<Socket> connect = CreateSocketAndConnect( ipAddress,port, 5000 ); |
| | | if (!connect.IsSuccess) return connect; |
| | | |
| | | OperateResult send = SendStringAndCheckReceive( connect.Content, 0, keyWord ); |
| | | if (!send.IsSuccess) return send; |
| | | |
| | | OperateResultExTwo<Integer, String> receive = ReceiveStringContentFromSocket( connect.Content ); |
| | | if (!receive.IsSuccess) return receive; |
| | | |
| | | if (receive.Content1 != 0) |
| | | { |
| | | OperateResult result = new OperateResult(); |
| | | result.Message = receive.Content2; |
| | | return result; |
| | | } |
| | | |
| | | AppSession appSession = new AppSession( ); |
| | | CoreSocket = connect.Content; |
| | | appSession.setWorkSocket(connect.Content); |
| | | BeginReceiveBackground( appSession ); |
| | | |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建数据推送服务 |
| | | * @param pushCallBack 触发数据推送的委托 |
| | | * @return 是否成功 |
| | | */ |
| | | public OperateResult CreatePush( ActionOperateExTwo<NetPushClient,String> pushCallBack ) |
| | | { |
| | | action = pushCallBack; |
| | | return CreatePush( ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 关闭消息推送的界面 |
| | | */ |
| | | public void ClosePush() |
| | | { |
| | | action = null; |
| | | if (CoreSocket != null && CoreSocket.isConnected()){ |
| | | Send(CoreSocket,Utilities.getBytes( 100 ) ); |
| | | } |
| | | CloseSocket(CoreSocket); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 本客户端的关键字 |
| | | * @return |
| | | */ |
| | | public String getKeyWord(){ |
| | | return keyWord; |
| | | } |
| | | |
| | | |
| | | private String ipAddress = ""; // IP地址 |
| | | private int port = 1000; // 端口号 |
| | | private String keyWord = ""; // 缓存的订阅关键字 |
| | | private ActionOperateExTwo<NetPushClient,String> action; // 服务器推送后的回调方法 |
| | | |
| | | |
| | | /** |
| | | * 获取本对象的字符串表示形式 |
| | | * @return 字符串 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "NetPushClient"; |
| | | } |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Enthernet.SimplifyNet; |
| | | |
| | | import com.zy.common.HslCommunication.Core.IMessage.HslMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.HslProtocol; |
| | | import com.zy.common.HslCommunication.Core.Net.NetHandle; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDoubleBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.RegularByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.util.UUID; |
| | | |
| | | |
| | | /** |
| | | * 同步访问的网络客户端 |
| | | */ |
| | | public class NetSimplifyClient extends NetworkDoubleBase<HslMessage,RegularByteTransform> |
| | | { |
| | | |
| | | |
| | | /** |
| | | * 实例化一个客户端的对象,用于和服务器通信 |
| | | * @param ipAddress Ip地址 |
| | | * @param port 端口号 |
| | | */ |
| | | public NetSimplifyClient(String ipAddress, int port) |
| | | { |
| | | this.setIpAddress(ipAddress); |
| | | this.setPort( port); |
| | | } |
| | | |
| | | /** |
| | | * 实例化一个客户端的对象,用于和服务器通信 |
| | | * @param ipAddress Ip地址 |
| | | * @param port 端口号 |
| | | * @param token 令牌 |
| | | */ |
| | | public NetSimplifyClient(String ipAddress, int port, UUID token) |
| | | { |
| | | this.setIpAddress(ipAddress); |
| | | this.setPort( port); |
| | | this.Token = token; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个客户端对象,需要手动指定Ip地址和端口 |
| | | */ |
| | | public NetSimplifyClient() |
| | | { |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 客户端向服务器进行请求,请求字符串数据 |
| | | * @param customer 用户的指令头 |
| | | * @param send 发送数据 |
| | | * @return 带结果说明的对象 |
| | | */ |
| | | public OperateResultExOne<String> ReadFromServer(NetHandle customer, String send) { |
| | | OperateResultExOne<String> result = new OperateResultExOne<String>(); |
| | | byte[] data = send.isEmpty() ? new byte[0] : Utilities.string2Byte(send); |
| | | OperateResultExOne<byte[]> temp = ReadFromServerBase(HslProtocol.ProtocolUserString, customer.get_CodeValue(), data); |
| | | result.IsSuccess = temp.IsSuccess; |
| | | result.ErrorCode = temp.ErrorCode; |
| | | result.Message = temp.Message; |
| | | if (temp.IsSuccess) { |
| | | result.Content = Utilities.byte2String(temp.Content); |
| | | } |
| | | temp = null; |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 客户端向服务器进行请求,请求字节数据 |
| | | * @param customer 用户的指令头 |
| | | * @param send 发送的字节内容 |
| | | * @return 带结果说明的对象 |
| | | */ |
| | | public OperateResultExOne<byte[]> ReadFromServer(NetHandle customer, byte[] send) { |
| | | return ReadFromServerBase(HslProtocol.ProtocolUserBytes, customer.get_CodeValue(), send); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 需要发送的底层数据 |
| | | * @param headCode 数据的指令头 |
| | | * @param customer 需要发送的底层数据 |
| | | * @param send 需要发送的底层数据 |
| | | * @return 带结果说明的对象 |
| | | */ |
| | | private OperateResultExOne<byte[]> ReadFromServerBase(int headCode, int customer, byte[] send) { |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer(HslProtocol.CommandBytes(headCode, customer, Token, send)); |
| | | if (!read.IsSuccess) { |
| | | return read; |
| | | } |
| | | |
| | | if(read.Content.length < HslProtocol.HeadByteLength){ |
| | | read.IsSuccess = false; |
| | | read.Message = "length is not correct :" +read.Content.length; |
| | | return read; |
| | | } |
| | | |
| | | byte[] headBytes = new byte[HslProtocol.HeadByteLength]; |
| | | byte[] contentBytes = new byte[read.Content.length - HslProtocol.HeadByteLength]; |
| | | |
| | | System.arraycopy(read.Content,0,headBytes,0,HslProtocol.HeadByteLength); |
| | | if (contentBytes.length > 0) { |
| | | System.arraycopy(read.Content, HslProtocol.HeadByteLength, contentBytes, 0, read.Content.length - HslProtocol.HeadByteLength); |
| | | } |
| | | |
| | | contentBytes = HslProtocol.CommandAnalysis(headBytes, contentBytes); |
| | | return OperateResultExOne.CreateSuccessResult(contentBytes); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取本对象的字符串表示形式 |
| | | * @return 字符串信息 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "NetSimplifyClient"; |
| | | } |
| | | |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/language/DefaultLanguage.java |
| | |
| | | package com.zy.gateway.core.language; |
| | | package com.zy.common.HslCommunication.Language; |
| | | |
| | | /** |
| | | * 系统的语言基类,默认也即是中文版本 |
File was renamed from src/main/java/com/zy/gateway/core/language/English.java |
| | |
| | | package com.zy.gateway.core.language; |
| | | package com.zy.common.HslCommunication.Language; |
| | | |
| | | /** |
| | | * English Version Text |
New file |
| | |
| | | package com.zy.common.HslCommunication.LogNet.Core; |
| | | |
| | | /** |
| | | * 日志文件输出模式 |
| | | */ |
| | | public enum GenerateMode { |
| | | |
| | | /** |
| | | * 按每个小时生成日志文件 |
| | | */ |
| | | ByEveryHour, |
| | | /** |
| | | * 按每天生成日志文件 |
| | | */ |
| | | ByEveryDay, |
| | | /** |
| | | * 按每个周生成日志文件 |
| | | */ |
| | | ByEveryWeek, |
| | | /** |
| | | * 按每个月生成日志文件 |
| | | */ |
| | | ByEveryMonth, |
| | | /** |
| | | * 按每季度生成日志文件 |
| | | */ |
| | | ByEverySeason , |
| | | /** |
| | | * 按每年生成日志文件 |
| | | */ |
| | | ByEveryYear, |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/log/HslMessageDegree.java |
| | |
| | | package com.zy.gateway.core.log; |
| | | package com.zy.common.HslCommunication.LogNet.Core; |
| | | |
| | | /** |
| | | * 日志的存储等级 |
New file |
| | |
| | | package com.zy.common.HslCommunication.LogNet.Core; |
| | | |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.util.Date; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | /** |
| | | * 单个日志的记录信息 |
| | | */ |
| | | public class HslMessageItem { |
| | | |
| | | private AtomicInteger IdNumber = new AtomicInteger(); |
| | | private long id =0; |
| | | private HslMessageDegree degree = HslMessageDegree.DEBUG; |
| | | private int threadId = 0; |
| | | private String text = ""; |
| | | private Date time = new Date(); |
| | | private String keyWord = ""; |
| | | |
| | | /** |
| | | * 默认的无参构造器 |
| | | */ |
| | | public HslMessageItem() |
| | | { |
| | | id = IdNumber.getAndIncrement(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 单个记录信息的标识ID,程序重新运行时清空 |
| | | * @return long数据类型 |
| | | */ |
| | | public long getId() { |
| | | return id; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取消息的等级 |
| | | * @return 消息等级 |
| | | */ |
| | | public HslMessageDegree getDegree() { |
| | | return degree; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息的等级 |
| | | * @param degree 消息等级 |
| | | */ |
| | | public void setDegree(HslMessageDegree degree) { |
| | | this.degree = degree; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取线程的标识 |
| | | * @return 线程id |
| | | */ |
| | | public int getThreadId() { |
| | | return threadId; |
| | | } |
| | | |
| | | /** |
| | | * 设置线程的标识 |
| | | * @param threadId 线程id |
| | | */ |
| | | public void setThreadId(int threadId) { |
| | | this.threadId = threadId; |
| | | } |
| | | |
| | | /** |
| | | * 获取消息文本 |
| | | * @return string类型数据 |
| | | */ |
| | | public String getText() { |
| | | return text; |
| | | } |
| | | |
| | | /** |
| | | * 设置消息文本 |
| | | * @param text 消息文本 |
| | | */ |
| | | public void setText(String text) { |
| | | this.text = text; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前的时间信息 |
| | | * @return 时间类型 |
| | | */ |
| | | public Date getTime() { |
| | | return time; |
| | | } |
| | | |
| | | /** |
| | | * 设置当前的时间 |
| | | * @param time 时间 |
| | | */ |
| | | public void setTime(Date time) { |
| | | this.time = time; |
| | | } |
| | | |
| | | /** |
| | | * 获取当前的关键字 |
| | | * @return string类型的关键字 |
| | | */ |
| | | public String getKeyWord() { |
| | | return keyWord; |
| | | } |
| | | |
| | | /** |
| | | * 设置当前的关键字 |
| | | * @param keyWord 关键字 |
| | | */ |
| | | public void setKeyWord(String keyWord) { |
| | | this.keyWord = keyWord; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * @return 字符串信息 |
| | | */ |
| | | @Override |
| | | public String toString( ) |
| | | { |
| | | if (keyWord == null || keyWord.length() == 0) |
| | | { |
| | | return "["+degree.toString()+"] "+ Utilities.getStringDateShort(time,"yyyy-MM-dd HH:mm:ss.fff") + " Thread["+String.format("D2",threadId)+"] "+text; |
| | | } |
| | | else |
| | | { |
| | | return "["+degree.toString()+"] "+ Utilities.getStringDateShort(time,"yyyy-MM-dd HH:mm:ss.fff") + " Thread["+String.format("D2",threadId)+"] " + keyWord +" : "+text; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串,剔除了关键字 |
| | | * @return 字符串数据 |
| | | */ |
| | | public String ToStringWithoutKeyword() |
| | | { |
| | | return "["+degree.toString()+"] "+ Utilities.getStringDateShort(time,"yyyy-MM-dd HH:mm:ss.fff") + " Thread["+String.format("D2",threadId)+"] "+text; |
| | | } |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/log/ILogNet.java |
| | |
| | | package com.zy.gateway.core.log; |
| | | package com.zy.common.HslCommunication.LogNet.Core; |
| | | |
| | | /** |
| | | * 日志的存储对象 |
| | |
| | | * 过滤掉指定的关键字的日志,该信息不存储,但仍然触发BeforeSaveToFile事件 |
| | | * @param keyword |
| | | */ |
| | | void FiltrateKeyword(String keyword); |
| | | void FiltrateKeyword( String keyword ); |
| | | |
| | | |
| | | /** |
New file |
| | |
| | | package com.zy.common.HslCommunication.ModBus; |
| | | |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.Address.DeviceAddressBase; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | |
| | | /** |
| | | * Modbus协议地址格式,可以携带站号,功能码,地址信息 |
| | | */ |
| | | public class ModbusAddress extends DeviceAddressBase { |
| | | |
| | | |
| | | |
| | | /** |
| | | * 实例化一个默认的对象 |
| | | */ |
| | | public ModbusAddress() { |
| | | Station = -1; |
| | | Function = ModbusInfo.ReadRegister; |
| | | setAddress(0); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个默认的对象,使用默认的地址初始化 |
| | | * @param address |
| | | */ |
| | | public ModbusAddress(String address) { |
| | | Station = -1; |
| | | Function = ModbusInfo.ReadRegister; |
| | | setAddress(0); |
| | | AnalysisAddress(address); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取站号 |
| | | * @return |
| | | */ |
| | | public int getStation() { |
| | | return Station; |
| | | } |
| | | |
| | | /** |
| | | * 设置站号 |
| | | * @param station |
| | | */ |
| | | public void setStation(int station) { |
| | | Station = station; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取功能码 |
| | | * @return |
| | | */ |
| | | public byte getFunction() { |
| | | return Function; |
| | | } |
| | | |
| | | /** |
| | | * 设置功能码 |
| | | * @param function |
| | | */ |
| | | public void setFunction(byte function) { |
| | | Function = function; |
| | | } |
| | | |
| | | private int Station = -1; |
| | | |
| | | private byte Function = -1; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 解析Modbus的地址码 |
| | | * @param address 地址 |
| | | */ |
| | | @Override |
| | | public void AnalysisAddress(String address) { |
| | | if (address.indexOf(';') < 0) { |
| | | // 正常地址,功能码03 |
| | | setAddress(Integer.parseInt(address)); |
| | | } else { |
| | | // 带功能码的地址 |
| | | String[] list = address.split(";"); |
| | | for (int i = 0; i < list.length; i++) { |
| | | if (list[i].charAt(0) == 's' || list[i].charAt(0) == 'S') { |
| | | // 站号信息 |
| | | this.Station = Integer.parseInt(list[i].substring(2)); |
| | | } else if (list[i].charAt(0) == 'x' || list[i].charAt(0) == 'X') { |
| | | this.Function = (byte) Integer.parseInt(list[i].substring(2)); |
| | | } else { |
| | | setAddress(Integer.parseInt(list[i])); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建一个读取线圈的字节对象 |
| | | * @param station 读取的站号 |
| | | * @param length 读取数据的长度 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateReadCoils(byte station, int length) { |
| | | byte[] buffer = new byte[6]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.ReadCoil; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = Utilities.getBytes(length)[1]; |
| | | buffer[5] = Utilities.getBytes(length)[0]; |
| | | return buffer; |
| | | } |
| | | |
| | | /** |
| | | * 创建一个读取离散输入的字节对象 |
| | | * @param station 读取的站号 |
| | | * @param length 读取数据的长度 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateReadDiscrete(byte station, int length) { |
| | | byte[] buffer = new byte[6]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.ReadDiscrete; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = Utilities.getBytes(length)[1]; |
| | | buffer[5] = Utilities.getBytes(length)[0]; |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建一个读取寄存器的字节对象 |
| | | * @param station 读取的站号 |
| | | * @param length 读取数据的长度 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateReadRegister(byte station, int length) { |
| | | byte[] buffer = new byte[6]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = Function; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = Utilities.getBytes(length)[1]; |
| | | buffer[5] = Utilities.getBytes(length)[0]; |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 创建一个写入单个线圈的指令 |
| | | * @param station 站号 |
| | | * @param value 值 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateWriteOneCoil(byte station, boolean value) { |
| | | byte[] buffer = new byte[6]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.WriteOneCoil; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = (byte) (value ? 0xFF : 0x00); |
| | | buffer[5] = 0x00; |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建一个写入单个寄存器的指令 |
| | | * @param station 站号 |
| | | * @param data 值 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateWriteOneRegister(byte station, byte[] data) { |
| | | byte[] buffer = new byte[6]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.WriteOneRegister; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = data[1]; |
| | | buffer[5] = data[0]; |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建一个写入批量线圈的指令 |
| | | * @param station 站号 |
| | | * @param values 值 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateWriteCoil(byte station, boolean[] values) { |
| | | byte[] data = SoftBasic.BoolArrayToByte(values); |
| | | byte[] buffer = new byte[7 + data.length]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.WriteCoil; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = (byte) (values.length / 256); |
| | | buffer[5] = (byte) (values.length % 256); |
| | | buffer[6] = (byte) (data.length); |
| | | System.arraycopy(data, 0, buffer, 7, data.length); |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 创建一个写入批量寄存器的指令 |
| | | * @param station 站号 |
| | | * @param values 值 |
| | | * @return 原始的modbus指令 |
| | | */ |
| | | public byte[] CreateWriteRegister(byte station, byte[] values) { |
| | | byte[] buffer = new byte[7 + values.length]; |
| | | buffer[0] = this.Station < 0 ? station : (byte) this.Station; |
| | | buffer[1] = ModbusInfo.WriteRegister; |
| | | buffer[2] = Utilities.getBytes(this.getAddress())[1]; |
| | | buffer[3] = Utilities.getBytes(this.getAddress())[0]; |
| | | buffer[4] = (byte) (values.length / 2 / 256); |
| | | buffer[5] = (byte) (values.length / 2 % 256); |
| | | buffer[6] = (byte) (values.length); |
| | | System.arraycopy(values, 0, buffer, 7, values.length); |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 地址新增指定的数 |
| | | * @param value 地址值 |
| | | * @return 新增后的地址信息 |
| | | */ |
| | | public ModbusAddress AddressAdd(int value) { |
| | | ModbusAddress address = new ModbusAddress(); |
| | | address.setAddress(getAddress() + value); |
| | | address.setFunction(getFunction()); |
| | | address.setStation(getStation()); |
| | | return address; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 地址新增1 |
| | | * @return 新增后的地址信息 |
| | | */ |
| | | public ModbusAddress AddressAdd() { |
| | | return AddressAdd(1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取本对象的字符串表示形式 |
| | | * @return 字符串数据 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | StringBuilder sb = new StringBuilder(); |
| | | if (Station >= 0) sb.append("s=" + Station + ";"); |
| | | if (Function >= 1) sb.append("x=" + Function + ";"); |
| | | sb.append(String.valueOf(getAddress())); |
| | | |
| | | return sb.toString(); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.ModBus; |
| | | |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * Modbus协议相关的一些信息 |
| | | */ |
| | | public class ModbusInfo { |
| | | |
| | | |
| | | /** |
| | | * 读取线圈 |
| | | */ |
| | | public static final byte ReadCoil = 0x01; |
| | | |
| | | /** |
| | | * 读取离散量 |
| | | */ |
| | | public static final byte ReadDiscrete = 0x02; |
| | | |
| | | |
| | | /** |
| | | * 读取寄存器 |
| | | */ |
| | | public static final byte ReadRegister = 0x03; |
| | | |
| | | /** |
| | | * 读取输入寄存器 |
| | | */ |
| | | public static final byte ReadInputRegister = 0x04; |
| | | |
| | | |
| | | /** |
| | | * 写单个线圈 |
| | | */ |
| | | public static final byte WriteOneCoil = 0x05; |
| | | |
| | | /** |
| | | * 写单个寄存器 |
| | | */ |
| | | public static final byte WriteOneRegister = 0x06; |
| | | |
| | | |
| | | /** |
| | | * 写多个线圈 |
| | | */ |
| | | public static final byte WriteCoil = 0x0F; |
| | | |
| | | /** |
| | | * 写多个寄存器 |
| | | */ |
| | | public static final byte WriteRegister = 0x10; |
| | | |
| | | |
| | | /***************************************************************************************** |
| | | * |
| | | * 本服务器和客户端支持的异常返回 |
| | | * |
| | | *******************************************************************************************/ |
| | | |
| | | |
| | | /** |
| | | * 不支持该功能码 |
| | | */ |
| | | public static final byte FunctionCodeNotSupport = 0x01; |
| | | |
| | | /** |
| | | * 该地址越界 |
| | | */ |
| | | public static final byte FunctionCodeOverBound = 0x02; |
| | | |
| | | /** |
| | | * 读取长度超过最大值 |
| | | */ |
| | | public static final byte FunctionCodeQuantityOver = 0x03; |
| | | |
| | | /** |
| | | * 读写异常 |
| | | */ |
| | | public static final byte FunctionCodeReadWriteException = 0x04; |
| | | |
| | | |
| | | /** |
| | | * 将modbus指令打包成Modbus-Tcp指令 |
| | | * |
| | | * @param value Modbus指令 |
| | | * @param id 消息的序号 |
| | | * @return Modbus-Tcp指令 |
| | | */ |
| | | public static byte[] PackCommandToTcp(byte[] value, int id) { |
| | | byte[] buffer = new byte[value.length + 6]; |
| | | buffer[0] = Utilities.getBytes(id)[1]; |
| | | buffer[1] = Utilities.getBytes(id)[0]; |
| | | |
| | | buffer[4] = Utilities.getBytes(value.length)[1]; |
| | | buffer[5] = Utilities.getBytes(value.length)[0]; |
| | | |
| | | System.arraycopy(value, 0, buffer, 6, value.length); |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 分析Modbus协议的地址信息,该地址适应于tcp及rtu模式 |
| | | * |
| | | * @param address 带格式的地址,比如"100","x=4;100","s=1;100","s=1;x=4;100" |
| | | * @param isStartWithZero 起始地址是否从0开始 |
| | | * @return 转换后的地址信息 |
| | | */ |
| | | public static OperateResultExOne<ModbusAddress> AnalysisReadAddress(String address, boolean isStartWithZero) { |
| | | try { |
| | | ModbusAddress mAddress = new ModbusAddress(address); |
| | | if (!isStartWithZero) { |
| | | if (mAddress.getAddress() < 1) throw new Exception("地址值在起始地址为1的情况下,必须大于1"); |
| | | mAddress.setAddress(mAddress.getAddress() - 1); |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult(mAddress); |
| | | } catch (Exception ex) { |
| | | OperateResultExOne<ModbusAddress> resultExOne = new OperateResultExOne<>(); |
| | | resultExOne.Message = ex.getMessage(); |
| | | return resultExOne; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 通过错误码来获取到对应的文本消息 |
| | | * |
| | | * @param code 错误码 |
| | | * @return 错误的文本描述 |
| | | */ |
| | | public static String GetDescriptionByErrorCode(byte code) { |
| | | switch (code) { |
| | | case ModbusInfo.FunctionCodeNotSupport: |
| | | return StringResources.Language.ModbusTcpFunctionCodeNotSupport(); |
| | | case ModbusInfo.FunctionCodeOverBound: |
| | | return StringResources.Language.ModbusTcpFunctionCodeOverBound(); |
| | | case ModbusInfo.FunctionCodeQuantityOver: |
| | | return StringResources.Language.ModbusTcpFunctionCodeQuantityOver(); |
| | | case ModbusInfo.FunctionCodeReadWriteException: |
| | | return StringResources.Language.ModbusTcpFunctionCodeReadWriteException(); |
| | | default: |
| | | return StringResources.Language.UnknownError(); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.ModBus; |
| | | |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftIncrementCount; |
| | | import com.zy.common.HslCommunication.Core.IMessage.ModbusTcpMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.DataFormat; |
| | | import com.zy.common.HslCommunication.Core.Transfer.ReverseWordTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.io.ByteArrayOutputStream; |
| | | |
| | | |
| | | /** |
| | | * Modbus-Tcp协议的客户端通讯类,方便的和服务器进行数据交互 |
| | | */ |
| | | public class ModbusTcpNet extends NetworkDeviceBase<ModbusTcpMessage, ReverseWordTransform> { |
| | | |
| | | |
| | | /** |
| | | * 实例化一个MOdbus-Tcp协议的客户端对象 |
| | | */ |
| | | public ModbusTcpNet() { |
| | | this.softIncrementCount = new SoftIncrementCount(65535, 0); |
| | | this.WordLength = 1; |
| | | this.station = 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 指定服务器地址,端口号,客户端自己的站号来初始化 |
| | | * |
| | | * @param ipAddress 服务器的Ip地址 |
| | | * @param port 服务器的端口号 |
| | | * @param station 客户端自身的站号,可以在读取的时候动态配置 |
| | | */ |
| | | public ModbusTcpNet(String ipAddress, int port, byte station) { |
| | | this.softIncrementCount = new SoftIncrementCount(65535, 0); |
| | | setIpAddress(ipAddress); |
| | | setPort(port); |
| | | this.WordLength = 1; |
| | | this.station = station; |
| | | } |
| | | |
| | | |
| | | private byte station = 0x01; // 本客户端的站号 |
| | | private SoftIncrementCount softIncrementCount; // 自增消息的对象 |
| | | private boolean isAddressStartWithZero = true; // 线圈值的地址值是否从零开始 |
| | | |
| | | |
| | | /** |
| | | * 获取起始地址是否从0开始 |
| | | * |
| | | * @return bool值 |
| | | */ |
| | | public boolean getAddressStartWithZero() { |
| | | return isAddressStartWithZero; |
| | | } |
| | | |
| | | /** |
| | | * 设置起始地址是否从0开始 |
| | | * |
| | | * @param addressStartWithZero true代表从0开始,false代表从1开始 |
| | | */ |
| | | public void setAddressStartWithZero(boolean addressStartWithZero) { |
| | | this.isAddressStartWithZero = addressStartWithZero; |
| | | } |
| | | |
| | | /** |
| | | * 获取站号 |
| | | * |
| | | * @return 站号 |
| | | */ |
| | | public byte getStation() { |
| | | return station; |
| | | } |
| | | |
| | | /** |
| | | * 设置站号 |
| | | * |
| | | * @param station 站号 |
| | | */ |
| | | public void setStation(byte station) { |
| | | this.station = station; |
| | | } |
| | | |
| | | /** |
| | | * 设置多字节数据的反转类型,适用于int,float,double,long类型的数据 |
| | | * |
| | | * @param dataFormat 数据类型 |
| | | */ |
| | | public void setDataFormat(DataFormat dataFormat) { |
| | | getByteTransform().setDataFormat(dataFormat); |
| | | } |
| | | |
| | | /** |
| | | * 获取多字节数据的反转类型,适用于int,float,double,long类型的数据 |
| | | * |
| | | * @return |
| | | */ |
| | | public DataFormat getDataFormat() { |
| | | return getByteTransform().getDataFormat(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 字符串数据是否发生反转 |
| | | * |
| | | * @return bool值 |
| | | */ |
| | | public boolean isStringReverse() { |
| | | return getByteTransform().IsStringReverse; |
| | | } |
| | | |
| | | /** |
| | | * 设置字符串数据是否反转 |
| | | * |
| | | * @param stringReverse bool值 |
| | | */ |
| | | public void setStringReverse(boolean stringReverse) { |
| | | getByteTransform().IsStringReverse = stringReverse; |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildReadCoilCommand(String address, short count) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadCoils(station, count), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | private OperateResultExOne<byte[]> BuildReadDiscreteCommand(String address, short length) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadDiscrete(station, length), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildReadRegisterCommand(String address, short length) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadRegister(station, length), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildReadRegisterCommand(ModbusAddress address, short length) { |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(address.CreateReadRegister(station, length), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildWriteOneCoilCommand(String address, boolean value) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteOneCoil(station, value), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildWriteOneRegisterCommand(String address, byte[] data) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteOneRegister(station, data), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildWriteCoilCommand(String address, boolean[] values) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteCoil(station, values), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | private OperateResultExOne<byte[]> BuildWriteRegisterCommand(String address, byte[] values) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | short messageId = (short) softIncrementCount.GetCurrentValue(); |
| | | // 生成最终tcp指令 |
| | | byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteRegister(station, values), messageId); |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查当前的Modbus-Tcp响应是否是正确的 |
| | | * |
| | | * @param send 发送的数据信息 |
| | | * @return 带是否成功的结果数据 |
| | | */ |
| | | private OperateResultExOne<byte[]> CheckModbusTcpResponse(byte[] send) { |
| | | OperateResultExOne<byte[]> result = ReadFromCoreServer(send); |
| | | if (result.IsSuccess) { |
| | | if ((send[7] + 0x80) == result.Content[7]) { |
| | | // 发生了错误 |
| | | result.IsSuccess = false; |
| | | result.Message = ModbusInfo.GetDescriptionByErrorCode(result.Content[8]); |
| | | result.ErrorCode = result.Content[8]; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 读取服务器的数据,需要指定不同的功能码 |
| | | * |
| | | * @param address 地址 |
| | | * @param length 长度 |
| | | * @return 结果数据 |
| | | */ |
| | | private OperateResultExOne<byte[]> ReadModBusBase(ModbusAddress address, short length) { |
| | | OperateResultExOne<byte[]> command = BuildReadRegisterCommand(address, length); |
| | | if (!command.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(command); |
| | | |
| | | OperateResultExOne<byte[]> resultBytes = CheckModbusTcpResponse(command.Content); |
| | | if (resultBytes.IsSuccess) { |
| | | // 二次数据处理 |
| | | if (resultBytes.Content.length >= 9) { |
| | | byte[] buffer = new byte[resultBytes.Content.length - 9]; |
| | | System.arraycopy(resultBytes.Content, 9, buffer, 0, buffer.length); |
| | | resultBytes.Content = buffer; |
| | | } |
| | | } |
| | | return resultBytes; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 读取服务器的数据,需要指定不同的功能码 |
| | | * |
| | | * @param code 指令 |
| | | * @param address 地址 |
| | | * @param length 长度 |
| | | * @return 指令字节信息 |
| | | */ |
| | | private OperateResultExOne<byte[]> ReadModBusBase(byte code, String address, short length) { |
| | | |
| | | OperateResultExOne<byte[]> command = null; |
| | | switch (code) { |
| | | case ModbusInfo.ReadCoil: { |
| | | command = BuildReadCoilCommand(address, length); |
| | | break; |
| | | } |
| | | case ModbusInfo.ReadDiscrete: { |
| | | command = BuildReadDiscreteCommand(address, length); |
| | | break; |
| | | } |
| | | case ModbusInfo.ReadRegister: { |
| | | command = BuildReadRegisterCommand(address, length); |
| | | break; |
| | | } |
| | | default: { |
| | | command = new OperateResultExOne<byte[]>(); |
| | | command.Message = StringResources.Language.ModbusTcpFunctionCodeNotSupport(); |
| | | break; |
| | | } |
| | | } |
| | | if (!command.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(command); |
| | | |
| | | OperateResultExOne<byte[]> resultBytes = CheckModbusTcpResponse(command.Content); |
| | | if (resultBytes.IsSuccess) { |
| | | // 二次数据处理 |
| | | if (resultBytes.Content.length >= 9) { |
| | | byte[] buffer = new byte[resultBytes.Content.length - 9]; |
| | | System.arraycopy(resultBytes, 9, buffer, 0, buffer.length); |
| | | resultBytes.Content = buffer; |
| | | } |
| | | } |
| | | return resultBytes; |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 读取线圈,需要指定起始地址 |
| | | * |
| | | * @param address 起始地址,格式为"1234" |
| | | * @return 带有成功标志的bool对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadCoil(String address) { |
| | | OperateResultExOne<byte[]> read = ReadModBusBase(ModbusInfo.ReadCoil, address, (short) 1); |
| | | if (!read.IsSuccess) return OperateResultExOne.<Boolean>CreateFailedResult(read); |
| | | |
| | | return GetBoolResultFromBytes(read); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 批量的读取线圈,需要指定起始地址,读取长度 |
| | | * |
| | | * @param address 起始地址,格式为"1234" |
| | | * @param length 读取长度 |
| | | * @return 带有成功标志的bool数组对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadCoil(String address, short length) { |
| | | OperateResultExOne<byte[]> read = ReadModBusBase(ModbusInfo.ReadCoil, address, length); |
| | | if (!read.IsSuccess) return OperateResultExOne.<boolean[]>CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(SoftBasic.ByteToBoolArray(read.Content, length)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 读取输入线圈,需要指定起始地址 |
| | | * |
| | | * @param address 起始地址,格式为"1234" |
| | | * @return 带有成功标志的bool对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadDiscrete(String address) { |
| | | OperateResultExOne<byte[]> read = ReadModBusBase(ModbusInfo.ReadDiscrete, address, (short) 1); |
| | | if (!read.IsSuccess) return OperateResultExOne.<Boolean>CreateFailedResult(read); |
| | | |
| | | return GetBoolResultFromBytes(read); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 批量的读取输入点,需要指定起始地址,读取长度 |
| | | * |
| | | * @param address 起始地址,格式为"1234" |
| | | * @param length 读取长度 |
| | | * @return 带有成功标志的bool数组对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadDiscrete(String address, short length) { |
| | | OperateResultExOne<byte[]> read = ReadModBusBase(ModbusInfo.ReadDiscrete, address, length); |
| | | if (!read.IsSuccess) return OperateResultExOne.<boolean[]>CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(SoftBasic.ByteToBoolArray(read.Content, length)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从Modbus服务器批量读取寄存器的信息,需要指定起始地址,读取长度 |
| | | * |
| | | * @param address 起始地址,格式为"1234",或者是带功能码格式03X1234 |
| | | * @param length 读取的数量 |
| | | * @return 带有成功标志的字节信息 |
| | | */ |
| | | @Override |
| | | public OperateResultExOne<byte[]> Read(String address, short length) { |
| | | OperateResultExOne<ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
| | | |
| | | int alreadyFinished = 0; |
| | | while (alreadyFinished < length) { |
| | | short lengthTmp = (short) Math.min((length - alreadyFinished), 120); |
| | | OperateResultExOne<byte[]> read = ReadModBusBase(analysis.Content.AddressAdd(alreadyFinished), lengthTmp); |
| | | if (!read.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(read); |
| | | |
| | | try { |
| | | outputStream.write(read.Content); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | alreadyFinished += lengthTmp; |
| | | } |
| | | |
| | | byte[] data = outputStream.toByteArray(); |
| | | try { |
| | | outputStream.close(); |
| | | } catch (Exception ex) { |
| | | |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult(data); |
| | | } |
| | | |
| | | /** |
| | | * 写一个寄存器数据 |
| | | * |
| | | * @param address 起始地址 |
| | | * @param high 高位 |
| | | * @param low 地位 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult WriteOneRegister(String address, byte high, byte low) { |
| | | OperateResultExOne<byte[]> command = BuildWriteOneRegisterCommand(address, new byte[]{high, low}); |
| | | if (!command.IsSuccess) { |
| | | return command; |
| | | } |
| | | |
| | | return CheckModbusTcpResponse(command.Content); |
| | | } |
| | | |
| | | /** |
| | | * 写一个寄存器数据 |
| | | * |
| | | * @param address 起始地址 |
| | | * @param value 写入值 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult WriteOneRegister(String address, short value) { |
| | | byte[] buffer = Utilities.getBytes(value); |
| | | return WriteOneRegister(address, buffer[1], buffer[0]); |
| | | } |
| | | |
| | | /** |
| | | * 将数据写入到Modbus的寄存器上去,需要指定起始地址和数据内容 |
| | | * |
| | | * @param address 起始地址,格式为"1234" |
| | | * @param value 写入的数据,长度根据data的长度来指示 |
| | | * @return 返回写入结果 |
| | | */ |
| | | @Override |
| | | public OperateResult Write(String address, byte[] value) { |
| | | OperateResultExOne<byte[]> command = BuildWriteRegisterCommand(address, value); |
| | | if (!command.IsSuccess) { |
| | | return command; |
| | | } |
| | | |
| | | return CheckModbusTcpResponse(command.Content); |
| | | } |
| | | |
| | | /** |
| | | * 写一个线圈信息,指定是否通断 |
| | | * |
| | | * @param address 起始地址 |
| | | * @param value 写入值 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult WriteCoil(String address, boolean value) { |
| | | OperateResultExOne<byte[]> command = BuildWriteOneCoilCommand(address, value); |
| | | if (!command.IsSuccess) { |
| | | return command; |
| | | } |
| | | |
| | | return CheckModbusTcpResponse(command.Content); |
| | | } |
| | | |
| | | /** |
| | | * 写线圈数组,指定是否通断 |
| | | * |
| | | * @param address 起始地址 |
| | | * @param values 写入值 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult WriteCoil(String address, boolean[] values) { |
| | | OperateResultExOne<byte[]> command = BuildWriteCoilCommand(address, values); |
| | | if (!command.IsSuccess) { |
| | | return command; |
| | | } |
| | | |
| | | return CheckModbusTcpResponse(command.Content); |
| | | } |
| | | |
| | | /** |
| | | * 向寄存器中写入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)); |
| | | } |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * @return 字符串信息 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "ModbusTcpNet[" + getIpAddress() + ":"+getPort()+"]"; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | /** |
| | | * 三菱PLC的数据类型,此处包含了几个常用的类型 |
| | | */ |
| | | public class MelsecA1EDataType { |
| | | /** |
| | | * 如果您清楚类型代号,可以根据值进行扩展 |
| | | * @param code 数据类型的代号 |
| | | * @param type 0或1,默认为0 |
| | | * @param asciiCode ASCII格式的类型信息 |
| | | * @param fromBase >指示地址的多少进制的,10或是16 |
| | | */ |
| | | public MelsecA1EDataType( byte[] code, byte type, String asciiCode, int fromBase ) |
| | | { |
| | | DataCode = code; |
| | | AsciiCode = asciiCode; |
| | | FromBase = fromBase; |
| | | if (type < 2) DataType = type; |
| | | } |
| | | |
| | | private byte[] DataCode = new byte[2]; |
| | | private byte DataType = 0x00; |
| | | private String AsciiCode = ""; |
| | | private int FromBase = 0; |
| | | |
| | | /** |
| | | * 类型的代号值(软元件代码,用于区分软元件类型,如:D,R) |
| | | * @return |
| | | */ |
| | | public byte[] getDataCode(){ |
| | | return DataCode; |
| | | } |
| | | |
| | | /** |
| | | * 数据的类型,0代表按字,1代表按位 |
| | | * @return |
| | | */ |
| | | public byte getDataType(){ |
| | | return DataType; |
| | | } |
| | | |
| | | /** |
| | | * 当以ASCII格式通讯时的类型描述 |
| | | * @return |
| | | */ |
| | | public String getAsciiCode(){ |
| | | return AsciiCode; |
| | | } |
| | | |
| | | /** |
| | | * 指示地址是10进制,还是16进制的 |
| | | * @return |
| | | */ |
| | | public int getFromBase(){ |
| | | return FromBase; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * X输入寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType X = new MelsecA1EDataType( new byte[] {0x58, 0x20}, (byte) 0x01, "X*", 8 ); |
| | | |
| | | /** |
| | | * Y输出寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType Y = new MelsecA1EDataType( new byte[] {0x59,0x20}, (byte)0x01, "Y*", 8 ); |
| | | |
| | | /** |
| | | * M中间寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType M = new MelsecA1EDataType( new byte[] {0x4D,0x20}, (byte)0x01, "M*", 10 ); |
| | | |
| | | /** |
| | | * S状态寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType S = new MelsecA1EDataType( new byte[] {0x53,0x20}, (byte)0x01, "S*", 10 ); |
| | | |
| | | /** |
| | | * D数据寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType D = new MelsecA1EDataType( new byte[] {0x44,0x20}, (byte)0x00, "D*", 10 ); |
| | | |
| | | /** |
| | | * R文件寄存器 |
| | | */ |
| | | public final static MelsecA1EDataType R = new MelsecA1EDataType( new byte[] { 0x52, 0x20 }, (byte)0x00, "R*", 10 ); |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | import com.zy.common.HslCommunication.Core.IMessage.MelsecA1EBinaryMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.RegularByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | |
| | | /** |
| | | * 三菱PLC通讯协议,采用A兼容1E帧协议实现,使用二进制码通讯,请根据实际型号来进行选取 |
| | | */ |
| | | public class MelsecA1ENet extends NetworkDeviceBase<MelsecA1EBinaryMessage,RegularByteTransform> { |
| | | |
| | | |
| | | /** |
| | | * 实例化三菱的A兼容1E帧协议的通讯对象 |
| | | */ |
| | | public MelsecA1ENet() { |
| | | WordLength = 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个三菱的A兼容1E帧协议的通讯对象 |
| | | * |
| | | * @param ipAddress PLCd的Ip地址 |
| | | * @param port PLC的端口 |
| | | */ |
| | | public MelsecA1ENet(String ipAddress, int port) { |
| | | WordLength = 1; |
| | | super.setIpAddress(ipAddress); |
| | | super.setPort(port); |
| | | } |
| | | |
| | | |
| | | private byte PLCNumber = (byte) (0xFF); // PLC编号 |
| | | |
| | | /** |
| | | * 获取PLC编号 |
| | | * |
| | | * @return PLC编号 |
| | | */ |
| | | public byte getPLCNumber() { |
| | | return PLCNumber; |
| | | } |
| | | |
| | | /** |
| | | * 设置PLC编号 |
| | | * |
| | | * @param plcNumber PLC编号 |
| | | */ |
| | | public void setPLCNumber(byte plcNumber) { |
| | | PLCNumber = plcNumber; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中读取想要的数据,返回读取结果 |
| | | * @param address 读取地址,格式为"M100","D100","W1A0" |
| | | * @param length 读取的数据长度,字最大值960,位最大值7168 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | @Override |
| | | public OperateResultExOne<byte[]> Read(String address, short length) { |
| | | // 获取指令 |
| | | OperateResultExOne<byte[]> command = BuildReadCommand( address, length, PLCNumber ); |
| | | if (!command.IsSuccess) return OperateResultExOne.CreateFailedResult( command ); |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult( read ); |
| | | |
| | | // 错误代码验证 |
| | | if (read.Content[1] != 0) return new OperateResultExOne<>( read.Content[1], StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 数据解析,需要传入是否使用位的参数 |
| | | return ExtractActualData( read.Content, command.Content[0] == 0x00 ); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @param length 读取的长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadBool(String address, short length) { |
| | | // 解析地址 |
| | | OperateResultExTwo<MelsecA1EDataType, Short> analysis = MelsecHelper.McA1EAnalysisAddress( address ); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult( analysis ); |
| | | |
| | | // 位读取校验 |
| | | if (analysis.Content1.getDataType() == 0x00) return new OperateResultExOne<boolean[]>( 0, StringResources.Language.MelsecReadBitInfo() ); |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = Read( address, length ); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult( read ); |
| | | |
| | | // 转化bool数组 |
| | | boolean[] result = new boolean[read.Content.length]; |
| | | for(int i=0;i<result.length;i++){ |
| | | if(read.Content[i] == 0x01) result[i] = true; |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult( result ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadBool(String address) { |
| | | OperateResultExOne<boolean[]> read = ReadBool(address, (short) 1); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(read.Content[0]); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC写入数据,数据格式为原始的字节类型 |
| | | * @param address 起始地址 |
| | | * @param value 原始数据 |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | public OperateResult Write(String address, byte[] value) { |
| | | // 解析指令 |
| | | OperateResultExOne<byte[]> command = BuildWriteCommand( address, value, PLCNumber ); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 错误码校验 (在A兼容1E协议中,结束代码后面紧跟的是异常信息的代码) |
| | | if (read.Content[1] != 0) return new OperateResultExOne<byte[]>( read.Content[1], StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 成功 |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param value 要写入的实际数据,长度为8的倍数 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean value) { |
| | | return Write(address, new boolean[]{value}); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param values 要写入的实际数据,可以指定任意的长度 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean[] values) { |
| | | byte[] buffer = new byte[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | buffer[i] = values[i] ? (byte) 0x01 : (byte) 0x00; |
| | | } |
| | | return Write(address, buffer); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取当前对象的字符串标识形式 |
| | | * @return 字符串信息 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "MelsecA1ENet"; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildReadCommand(String address, short length) { |
| | | return BuildReadCommand(address,length,(byte)0xFF); |
| | | } |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @param plcNumber PLC号 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildReadCommand(String address, short length, byte plcNumber) { |
| | | OperateResultExTwo<MelsecA1EDataType, Short> analysis = MelsecHelper.McA1EAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | byte subtitle = analysis.Content1.getDataType() == 0x01 ? (byte)0x00 : (byte)0x01; |
| | | |
| | | byte[] _PLCCommand = new byte[12]; |
| | | _PLCCommand[0] = subtitle; // 副标题 |
| | | _PLCCommand[1] = plcNumber; // PLC号 |
| | | _PLCCommand[2] = 0x0A; // CPU监视定时器(L)这里设置为0x00,0x0A,等待CPU返回的时间为10*250ms=2.5秒 |
| | | _PLCCommand[3] = 0x00; // CPU监视定时器(H) |
| | | _PLCCommand[4] = (byte)(analysis.Content2 % 256); // 起始软元件(开始读取的地址) |
| | | _PLCCommand[5] = (byte)(analysis.Content2 / 256); |
| | | _PLCCommand[6] = 0x00; |
| | | _PLCCommand[7] = 0x00; |
| | | _PLCCommand[8] = analysis.Content1.getDataCode()[1]; // 软元件代码(L) |
| | | _PLCCommand[9] = analysis.Content1.getDataCode()[0]; // 软元件代码(H) |
| | | _PLCCommand[10] = (byte)(length % 256); // 软元件点数 |
| | | _PLCCommand[11] = 0x00; |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(_PLCCommand); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param address 起始地址 |
| | | * @param value 值 |
| | | * @return 结果 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value) { |
| | | return BuildWriteCommand(address,value,(byte)0xFF); |
| | | } |
| | | |
| | | /** |
| | | * 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param address 起始地址 |
| | | * @param value 值 |
| | | * @param plcNumber PLC号 |
| | | * @return 结果 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value, byte plcNumber) { |
| | | OperateResultExTwo<MelsecA1EDataType, Short> analysis = MelsecHelper.McA1EAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | int length = -1; |
| | | if (analysis.Content1.getDataType() == 1) |
| | | { |
| | | // 按照位写入的操作,数据需要重新计算 |
| | | length = value.length; |
| | | value = MelsecHelper.TransBoolArrayToByteData( value ); |
| | | } |
| | | |
| | | byte subtitle = analysis.Content1.getDataType() == 0x01 ? (byte)0x02 : (byte)0x03; |
| | | |
| | | byte[] _PLCCommand = new byte[12 + value.length]; |
| | | _PLCCommand[0] = subtitle; // 副标题 |
| | | _PLCCommand[1] = plcNumber; // PLC号 |
| | | _PLCCommand[2] = 0x0A; // CPU监视定时器(L)这里设置为0x00,0x0A,等待CPU返回的时间为10*250ms=2.5秒 |
| | | _PLCCommand[3] = 0x00; // CPU监视定时器(H) |
| | | _PLCCommand[4] = (byte)(analysis.Content2 % 256); // 起始软元件(开始读取的地址) |
| | | _PLCCommand[5] = (byte)(analysis.Content2 / 256); |
| | | _PLCCommand[6] = 0x00; |
| | | _PLCCommand[7] = 0x00; |
| | | _PLCCommand[8] = analysis.Content1.getDataCode()[1]; // 软元件代码(L) |
| | | _PLCCommand[9] = analysis.Content1.getDataCode()[0]; // 软元件代码(H) |
| | | _PLCCommand[10] = (byte)(length % 256); // 软元件点数 |
| | | _PLCCommand[11] = 0x00; |
| | | |
| | | // 判断是否进行位操作 |
| | | if (analysis.Content1.getDataType() == 1) { |
| | | if (length > 0) { |
| | | _PLCCommand[10] = (byte)(length % 256); // 软元件点数 |
| | | } |
| | | else { |
| | | _PLCCommand[10] = (byte)(value.length * 2 % 256); // 软元件点数 |
| | | } |
| | | } else { |
| | | _PLCCommand[10] = (byte)(value.length / 2 % 256); // 软元件点数 |
| | | } |
| | | |
| | | System.arraycopy(value, 0, _PLCCommand, 12, value.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(_PLCCommand); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取 |
| | | * @param response 反馈的数据内容 |
| | | * @param isBit 是否位读取 |
| | | * @return 解析后的结果对象 |
| | | */ |
| | | public static OperateResultExOne<byte[]> ExtractActualData( byte[] response, boolean isBit ) |
| | | { |
| | | if (isBit) |
| | | { |
| | | // 位读取 |
| | | byte[] Content = new byte[(response.length - 2) * 2]; |
| | | for (int i = 2; i < response.length; i++) |
| | | { |
| | | if ((response[i] & 0x10) == 0x10) |
| | | { |
| | | Content[(i - 2) * 2 + 0] = 0x01; |
| | | } |
| | | |
| | | if ((response[i] & 0x01) == 0x01) |
| | | { |
| | | Content[(i - 2) * 2 + 1] = 0x01; |
| | | } |
| | | } |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | else |
| | | { |
| | | // 字读取 |
| | | byte[] Content = new byte[response.length - 2]; |
| | | System.arraycopy(response,2,Content,0,Content.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * 所有三菱通讯类的通用辅助工具类,包含了一些通用的静态方法,可以使用本类来获取一些原始的报文信息。详细的操作参见例子 |
| | | */ |
| | | public class MelsecHelper { |
| | | |
| | | /** |
| | | * 解析A1E协议数据地址 |
| | | * @param address 数据地址 |
| | | * @return 解析值 |
| | | */ |
| | | public static OperateResultExTwo<MelsecA1EDataType, Short> McA1EAnalysisAddress( String address ) |
| | | { |
| | | OperateResultExTwo<MelsecA1EDataType, Short> result = new OperateResultExTwo<MelsecA1EDataType, Short>(); |
| | | try { |
| | | switch (address.charAt(0)) { |
| | | case 'X': |
| | | case 'x': { |
| | | result.Content1 = MelsecA1EDataType.X; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.X.getFromBase()); |
| | | break; |
| | | } |
| | | case 'Y': |
| | | case 'y': { |
| | | result.Content1 = MelsecA1EDataType.Y; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.Y.getFromBase()); |
| | | break; |
| | | } |
| | | case 'M': |
| | | case 'm': { |
| | | result.Content1 = MelsecA1EDataType.M; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.M.getFromBase()); |
| | | break; |
| | | } |
| | | case 'S': |
| | | case 's': { |
| | | result.Content1 = MelsecA1EDataType.S; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.S.getFromBase()); |
| | | break; |
| | | } |
| | | case 'D': |
| | | case 'd': { |
| | | result.Content1 = MelsecA1EDataType.D; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.D.getFromBase()); |
| | | break; |
| | | } |
| | | case 'R': |
| | | case 'r': { |
| | | result.Content1 = MelsecA1EDataType.R; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecA1EDataType.R.getFromBase()); |
| | | break; |
| | | } |
| | | default: |
| | | throw new Exception("输入的类型不支持,请重新输入"); |
| | | } |
| | | } catch (Exception ex) { |
| | | result.Message = "地址格式填写错误:" + ex.getMessage(); |
| | | return result; |
| | | } |
| | | |
| | | result.IsSuccess = true; |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 解析数据地址 |
| | | * @param address 数据地址 |
| | | * @return 解析值 |
| | | */ |
| | | public static OperateResultExTwo<MelsecMcDataType, Short> McAnalysisAddress( String address ) |
| | | { |
| | | OperateResultExTwo<MelsecMcDataType, Short> result = new OperateResultExTwo<MelsecMcDataType, Short>(); |
| | | try { |
| | | switch (address.charAt(0)) { |
| | | case 'M': |
| | | case 'm': { |
| | | result.Content1 = MelsecMcDataType.M; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.M.getFromBase()); |
| | | break; |
| | | } |
| | | case 'X': |
| | | case 'x': { |
| | | result.Content1 = MelsecMcDataType.X; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.X.getFromBase()); |
| | | break; |
| | | } |
| | | case 'Y': |
| | | case 'y': { |
| | | result.Content1 = MelsecMcDataType.Y; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.Y.getFromBase()); |
| | | break; |
| | | } |
| | | case 'D': |
| | | case 'd': { |
| | | result.Content1 = MelsecMcDataType.D; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.D.getFromBase()); |
| | | break; |
| | | } |
| | | case 'W': |
| | | case 'w': { |
| | | result.Content1 = MelsecMcDataType.W; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.W.getFromBase()); |
| | | break; |
| | | } |
| | | case 'L': |
| | | case 'l': { |
| | | result.Content1 = MelsecMcDataType.L; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.L.getFromBase()); |
| | | break; |
| | | } |
| | | case 'F': |
| | | case 'f': { |
| | | result.Content1 = MelsecMcDataType.F; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.F.getFromBase()); |
| | | break; |
| | | } |
| | | case 'V': |
| | | case 'v': { |
| | | result.Content1 = MelsecMcDataType.V; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.V.getFromBase()); |
| | | break; |
| | | } |
| | | case 'B': |
| | | case 'b': { |
| | | result.Content1 = MelsecMcDataType.B; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.B.getFromBase()); |
| | | break; |
| | | } |
| | | case 'R': |
| | | case 'r': { |
| | | result.Content1 = MelsecMcDataType.R; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.R.getFromBase()); |
| | | break; |
| | | } |
| | | case 'S': |
| | | case 's': { |
| | | result.Content1 = MelsecMcDataType.S; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.S.getFromBase()); |
| | | break; |
| | | } |
| | | case 'Z': |
| | | case 'z': { |
| | | result.Content1 = MelsecMcDataType.Z; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.Z.getFromBase()); |
| | | break; |
| | | } |
| | | case 'T': |
| | | case 't': { |
| | | result.Content1 = MelsecMcDataType.T; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.T.getFromBase()); |
| | | break; |
| | | } |
| | | case 'C': |
| | | case 'c': { |
| | | result.Content1 = MelsecMcDataType.C; |
| | | result.Content2 = Short.parseShort(address.substring(1), MelsecMcDataType.C.getFromBase()); |
| | | break; |
| | | } |
| | | default: |
| | | throw new Exception("输入的类型不支持,请重新输入"); |
| | | } |
| | | } catch (Exception ex) { |
| | | result.Message = "地址格式填写错误:" + ex.getMessage(); |
| | | return result; |
| | | } |
| | | |
| | | result.IsSuccess = true; |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从字节构建一个ASCII格式的地址字节 |
| | | * @param value 字节信息 |
| | | * @return ASCII格式的地址 |
| | | */ |
| | | public static byte[] BuildBytesFromData(byte value ) |
| | | { |
| | | return Utilities.getBytes(String.format("%02x",value),"ASCII"); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从short数据构建一个ASCII格式地址字节 |
| | | * @param value short值 |
| | | * @return ASCII格式的地址 |
| | | */ |
| | | public static byte[] BuildBytesFromData( short value ) |
| | | { |
| | | return Utilities.getBytes(String.format("%04x",value),"ASCII"); |
| | | } |
| | | |
| | | /** |
| | | * 从int数据构建一个ASCII格式地址字节 |
| | | * @param value int值 |
| | | * @return ASCII格式的地址 |
| | | */ |
| | | public static byte[] BuildBytesFromData( int value ) |
| | | { |
| | | return Utilities.getBytes(String.format("%04x",value),"ASCII"); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从三菱的地址中构建MC协议的6字节的ASCII格式的地址 |
| | | * @param address 三菱地址 |
| | | * @param type 三菱的数据类型 |
| | | * @return 6字节的ASCII格式的地址 |
| | | */ |
| | | public static byte[] BuildBytesFromAddress( int address, MelsecMcDataType type ) |
| | | { |
| | | return Utilities.getBytes(String.format(type.getFromBase() == 10 ? "%06d" : "%06x",address),"ASCII"); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从字节数组构建一个ASCII格式的地址字节 |
| | | * @param value 字节信息 |
| | | * @return ASCII格式的地址 |
| | | */ |
| | | public static byte[] BuildBytesFromData( byte[] value ) |
| | | { |
| | | byte[] buffer = new byte[value.length * 2]; |
| | | for (int i = 0; i < value.length; i++) |
| | | { |
| | | byte[] data = BuildBytesFromData( value[i] ); |
| | | buffer[2*i+0] = data[0]; |
| | | buffer[2*i+1] = data[1]; |
| | | } |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 将0,1,0,1的字节数组压缩成三菱格式的字节数组来表示开关量的 |
| | | * @param value 原始的数据字节 |
| | | * @return 压缩过后的数据字节 |
| | | */ |
| | | public static byte[] TransBoolArrayToByteData( byte[] value ) |
| | | { |
| | | int length = value.length % 2 == 0 ? value.length / 2 : (value.length / 2) + 1; |
| | | byte[] buffer = new byte[length]; |
| | | |
| | | for (int i = 0; i < length; i++) |
| | | { |
| | | if (value[i * 2 + 0] != 0x00) buffer[i] += 0x10; |
| | | if ((i * 2 + 1) < value.length) |
| | | { |
| | | if (value[i * 2 + 1] != 0x00) buffer[i] += 0x01; |
| | | } |
| | | } |
| | | |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 计算Fx协议指令的和校验信息 |
| | | * @param data 字节数据 |
| | | * @return 校验之后的数据 |
| | | */ |
| | | public static byte[] FxCalculateCRC( byte[] data ) |
| | | { |
| | | int sum = 0; |
| | | for (int i = 1; i < data.length - 2; i++) |
| | | { |
| | | sum += data[i]; |
| | | } |
| | | return BuildBytesFromData( (byte)sum ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 检查指定的和校验是否是正确的 |
| | | * @param data 字节数据 |
| | | * @return 是否成功 |
| | | */ |
| | | public static boolean CheckCRC( byte[] data ) |
| | | { |
| | | byte[] crc = FxCalculateCRC( data ); |
| | | if (crc[0] != data[data.length - 2]) return false; |
| | | if (crc[1] != data[data.length - 1]) return false; |
| | | return true; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | import com.zy.common.HslCommunication.Core.IMessage.MelsecQnA3EAsciiMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.RegularByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | |
| | | /** |
| | | * 三菱PLC通讯类,采用Qna兼容3E帧协议实现,需要在PLC侧先的以太网模块先进行配置,必须为ASCII通讯格式 |
| | | */ |
| | | public class MelsecMcAsciiNet extends NetworkDeviceBase<MelsecQnA3EAsciiMessage, RegularByteTransform> { |
| | | |
| | | /** |
| | | * 实例化三菱的Qna兼容3E帧协议的通讯对象 |
| | | */ |
| | | public MelsecMcAsciiNet() { |
| | | WordLength = 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个三菱的Qna兼容3E帧协议的通讯对象 |
| | | * @param ipAddress PLC的Ip地址 |
| | | * @param port PLC的端口 |
| | | */ |
| | | public MelsecMcAsciiNet(String ipAddress, int port) { |
| | | WordLength = 1; |
| | | setIpAddress(ipAddress); |
| | | setPort(port); |
| | | } |
| | | |
| | | |
| | | private byte NetworkNumber = 0x00; // 网络号 |
| | | private byte NetworkStationNumber = 0x00; // 网络站号 |
| | | |
| | | /** |
| | | * 获取网络号 |
| | | * |
| | | * @return |
| | | */ |
| | | public byte getNetworkNumber() { |
| | | return NetworkNumber; |
| | | } |
| | | |
| | | /** |
| | | * 设置网络号 |
| | | * |
| | | * @param networkNumber |
| | | */ |
| | | public void setNetworkNumber(byte networkNumber) { |
| | | NetworkNumber = networkNumber; |
| | | } |
| | | |
| | | /** |
| | | * 获取网络站号 |
| | | * |
| | | * @return |
| | | */ |
| | | public byte getNetworkStationNumber() { |
| | | return NetworkStationNumber; |
| | | } |
| | | |
| | | /** |
| | | * 设置网络站号 |
| | | * |
| | | * @param networkStationNumber |
| | | */ |
| | | public void setNetworkStationNumber(byte networkStationNumber) { |
| | | NetworkStationNumber = networkStationNumber; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中读取想要的数据,返回读取结果 |
| | | * @param address 读取地址,格式为"M100","D100","W1A0" |
| | | * @param length 读取的数据长度,字最大值960,位最大值7168 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | @Override |
| | | public OperateResultExOne<byte[]> Read(String address, short length) { |
| | | //获取指令 |
| | | OperateResultExOne<byte[]> command = BuildReadCommand( address, length, NetworkNumber, NetworkStationNumber ); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 错误代码验证 |
| | | short errorCode = Short.parseShort(Utilities.getString(read.Content,18,4,"ASCII"), 16 ); |
| | | if (errorCode != 0) return new OperateResultExOne<>( errorCode, StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 数据解析,需要传入是否使用位的参数 |
| | | return ExtractActualData( read.Content, command.Content[29] == 0x31 ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @param length 读取的长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadBool(String address, short length) { |
| | | // 解析地址 |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress( address ); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult( analysis ); |
| | | |
| | | // 位读取校验 |
| | | if (analysis.Content1.getDataType() == 0x00) return new OperateResultExOne<>( StringResources.Language.MelsecReadBitInfo() ); |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = Read( address, length ); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult( read ); |
| | | |
| | | // 转化bool数组 |
| | | boolean[] content = new boolean[read.Content.length]; |
| | | for (int i = 0; i < read.Content.length; i++) { |
| | | content[i] = read.Content[i] == 0x01; |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult( content ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadBool(String address) { |
| | | OperateResultExOne<boolean[]> read = ReadBool(address, (short) 1); |
| | | if (!read.IsSuccess) return OperateResultExOne.<Boolean>CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.<Boolean>CreateSuccessResult(read.Content[0]); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 向PLC写入数据,数据格式为原始的字节类型 |
| | | * @param address 起始地址 |
| | | * @param value 原始数据 |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | public OperateResult Write(String address, byte[] value) { |
| | | // 解析指令 |
| | | OperateResultExOne<byte[]> command = BuildWriteCommand( address, value, NetworkNumber, NetworkStationNumber ); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 错误码验证 |
| | | short errorCode = Short.parseShort( Utilities.getString( read.Content, 18, 4 ,"ASCII"), 16 ); |
| | | if (errorCode != 0) return new OperateResultExOne<byte[]>( errorCode, StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 写入成功 |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param value 要写入的实际数据,true 或者是 false |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean value) { |
| | | return Write(address, new boolean[]{value}); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param values 要写入的实际数据,可以指定任意的长度 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean[] values) { |
| | | byte[] buffer = new byte[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | if (values[i]) buffer[i] = 0x01; |
| | | } |
| | | return Write(address, buffer); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * @return 字符串 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "MelsecMcNet"; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | public static OperateResultExOne< byte[]> BuildReadCommand(String address, short length, byte networkNumber, byte networkStationNumber) { |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | // 默认信息----注意:高低字节交错 |
| | | |
| | | try { |
| | | byte[] _PLCCommand = new byte[42]; |
| | | _PLCCommand[0] = 0x35; // 副标题 |
| | | _PLCCommand[1] = 0x30; |
| | | _PLCCommand[2] = 0x30; |
| | | _PLCCommand[3] = 0x30; |
| | | _PLCCommand[4] = MelsecHelper.BuildBytesFromData(networkNumber)[0]; // 网络号 |
| | | _PLCCommand[5] = MelsecHelper.BuildBytesFromData(networkNumber)[1]; |
| | | _PLCCommand[6] = 0x46; // PLC编号 |
| | | _PLCCommand[7] = 0x46; |
| | | _PLCCommand[8] = 0x30; // 目标模块IO编号 |
| | | _PLCCommand[9] = 0x33; |
| | | _PLCCommand[10] = 0x46; |
| | | _PLCCommand[11] = 0x46; |
| | | _PLCCommand[12] = MelsecHelper.BuildBytesFromData(networkStationNumber)[0]; // 目标模块站号 |
| | | _PLCCommand[13] = MelsecHelper.BuildBytesFromData(networkStationNumber)[1]; |
| | | _PLCCommand[14] = 0x30; // 请求数据长度 |
| | | _PLCCommand[15] = 0x30; |
| | | _PLCCommand[16] = 0x31; |
| | | _PLCCommand[17] = 0x38; |
| | | _PLCCommand[18] = 0x30; // CPU监视定时器 |
| | | _PLCCommand[19] = 0x30; |
| | | _PLCCommand[20] = 0x31; |
| | | _PLCCommand[21] = 0x30; |
| | | _PLCCommand[22] = 0x30; // 批量读取数据命令 |
| | | _PLCCommand[23] = 0x34; |
| | | _PLCCommand[24] = 0x30; |
| | | _PLCCommand[25] = 0x31; |
| | | _PLCCommand[26] = 0x30; // 以点为单位还是字为单位成批读取 |
| | | _PLCCommand[27] = 0x30; |
| | | _PLCCommand[28] = 0x30; |
| | | _PLCCommand[29] = analysis.Content1.getDataType() == 0 ? (byte) 0x30 : (byte) 0x31; |
| | | _PLCCommand[30] = (analysis.Content1.getAsciiCode().getBytes("ASCII"))[0]; // 软元件类型 |
| | | _PLCCommand[31] = (analysis.Content1.getAsciiCode().getBytes("ASCII"))[1]; |
| | | _PLCCommand[32] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[0]; // 起始地址的地位 |
| | | _PLCCommand[33] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[1]; |
| | | _PLCCommand[34] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[2]; |
| | | _PLCCommand[35] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[3]; |
| | | _PLCCommand[36] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[4]; |
| | | _PLCCommand[37] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[5]; |
| | | _PLCCommand[38] = MelsecHelper.BuildBytesFromData(length)[0]; // 软元件点数 |
| | | _PLCCommand[39] = MelsecHelper.BuildBytesFromData(length)[1]; |
| | | _PLCCommand[40] = MelsecHelper.BuildBytesFromData(length)[2]; |
| | | _PLCCommand[41] = MelsecHelper.BuildBytesFromData(length)[3]; |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( _PLCCommand ); |
| | | } |
| | | catch (Exception ex){ |
| | | return new OperateResultExOne<byte[]>(ex.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param address 起始地址 |
| | | * @param value 实际的数据 |
| | | * @return 命令数据 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value, byte networkNumber, byte networkStationNumber) { |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | // 预处理指令 |
| | | if (analysis.Content1.getDataType() == 0x01) |
| | | { |
| | | // 位写入 |
| | | byte[] buffer = new byte[value.length]; |
| | | for(int i=0;i<buffer.length;i++){ |
| | | buffer[i] = value[i] == 0x00? (byte)0x30 : (byte)0x31; |
| | | } |
| | | value = buffer; |
| | | } |
| | | else |
| | | { |
| | | // 字写入 |
| | | byte[] buffer = new byte[value.length * 2]; |
| | | for (int i = 0; i < value.length / 2; i++) |
| | | { |
| | | byte[] tmp = MelsecHelper.BuildBytesFromData( Utilities.getShort( value, i * 2 ) ); |
| | | System.arraycopy(tmp,0,buffer,4*i,4); |
| | | } |
| | | value = buffer; |
| | | } |
| | | |
| | | byte[] _PLCCommand = new byte[42 + value.length]; |
| | | |
| | | try { |
| | | _PLCCommand[0] = 0x35; // 副标题 |
| | | _PLCCommand[1] = 0x30; |
| | | _PLCCommand[2] = 0x30; |
| | | _PLCCommand[3] = 0x30; |
| | | _PLCCommand[4] = MelsecHelper.BuildBytesFromData(networkNumber)[0]; // 网络号 |
| | | _PLCCommand[5] = MelsecHelper.BuildBytesFromData(networkNumber)[1]; |
| | | _PLCCommand[6] = 0x46; // PLC编号 |
| | | _PLCCommand[7] = 0x46; |
| | | _PLCCommand[8] = 0x30; // 目标模块IO编号 |
| | | _PLCCommand[9] = 0x33; |
| | | _PLCCommand[10] = 0x46; |
| | | _PLCCommand[11] = 0x46; |
| | | _PLCCommand[12] = MelsecHelper.BuildBytesFromData(networkStationNumber)[0]; // 目标模块站号 |
| | | _PLCCommand[13] = MelsecHelper.BuildBytesFromData(networkStationNumber)[1]; |
| | | _PLCCommand[14] = MelsecHelper.BuildBytesFromData((_PLCCommand.length - 18))[0]; // 请求数据长度 |
| | | _PLCCommand[15] = MelsecHelper.BuildBytesFromData((_PLCCommand.length - 18))[1]; |
| | | _PLCCommand[16] = MelsecHelper.BuildBytesFromData((_PLCCommand.length - 18))[2]; |
| | | _PLCCommand[17] = MelsecHelper.BuildBytesFromData((_PLCCommand.length - 18))[3]; |
| | | _PLCCommand[18] = 0x30; // CPU监视定时器 |
| | | _PLCCommand[19] = 0x30; |
| | | _PLCCommand[20] = 0x31; |
| | | _PLCCommand[21] = 0x30; |
| | | _PLCCommand[22] = 0x31; // 批量写入的命令 |
| | | _PLCCommand[23] = 0x34; |
| | | _PLCCommand[24] = 0x30; |
| | | _PLCCommand[25] = 0x31; |
| | | _PLCCommand[26] = 0x30; // 子命令 |
| | | _PLCCommand[27] = 0x30; |
| | | _PLCCommand[28] = 0x30; |
| | | _PLCCommand[29] = analysis.Content1.getDataType() == 0 ? (byte) 0x30 : (byte) 0x31; |
| | | _PLCCommand[30] = (analysis.Content1.getAsciiCode().getBytes("ASCII"))[0]; // 软元件类型 |
| | | _PLCCommand[31] = (analysis.Content1.getAsciiCode().getBytes("ASCII"))[1]; |
| | | _PLCCommand[32] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[0]; // 起始地址的地位 |
| | | _PLCCommand[33] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[1]; |
| | | _PLCCommand[34] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[2]; |
| | | _PLCCommand[35] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[3]; |
| | | _PLCCommand[36] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[4]; |
| | | _PLCCommand[37] = MelsecHelper.BuildBytesFromAddress(analysis.Content2, analysis.Content1)[5]; |
| | | |
| | | // 判断是否进行位操作 |
| | | if (analysis.Content1.getDataType() == 1) { |
| | | _PLCCommand[38] = MelsecHelper.BuildBytesFromData( value.length)[0]; // 软元件点数 |
| | | _PLCCommand[39] = MelsecHelper.BuildBytesFromData( value.length)[1]; |
| | | _PLCCommand[40] = MelsecHelper.BuildBytesFromData( value.length)[2]; |
| | | _PLCCommand[41] = MelsecHelper.BuildBytesFromData( value.length)[3]; |
| | | } else { |
| | | _PLCCommand[38] = MelsecHelper.BuildBytesFromData( (value.length / 4))[0]; // 软元件点数 |
| | | _PLCCommand[39] = MelsecHelper.BuildBytesFromData( (value.length / 4))[1]; |
| | | _PLCCommand[40] = MelsecHelper.BuildBytesFromData( (value.length / 4))[2]; |
| | | _PLCCommand[41] = MelsecHelper.BuildBytesFromData( (value.length / 4))[3]; |
| | | } |
| | | System.arraycopy(value,0,_PLCCommand,42,value.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(_PLCCommand); |
| | | |
| | | } |
| | | catch (Exception ex){ |
| | | return new OperateResultExOne<>(ex.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取 |
| | | * @param response 反馈的数据内容 |
| | | * @param isBit 是否位读取 |
| | | * @return 解析后的结果对象 |
| | | */ |
| | | public static OperateResultExOne<byte[]> ExtractActualData( byte[] response, boolean isBit ) |
| | | { |
| | | if (isBit) |
| | | { |
| | | // 位读取 |
| | | byte[] Content = new byte[response.length - 22]; |
| | | for (int i = 22; i < response.length; i++) |
| | | { |
| | | if (response[i] == 0x30) |
| | | { |
| | | Content[i - 22] = 0x00; |
| | | } |
| | | else |
| | | { |
| | | Content[i - 22] = 0x01; |
| | | } |
| | | } |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | else |
| | | { |
| | | // 字读取 |
| | | byte[] Content = new byte[(response.length - 22) / 2]; |
| | | for (int i = 0; i < Content.length / 2; i++) |
| | | { |
| | | int tmp = Integer.parseInt( Utilities.getString( response, i * 4 + 22, 4 ,"ASCII"), 16 ); |
| | | byte[] buffer = Utilities.getBytes(tmp); |
| | | |
| | | Content[i*2+0] = buffer[0]; |
| | | Content[i*2+1] = buffer[1]; |
| | | } |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | |
| | | /** |
| | | * 三菱的数据类型 |
| | | */ |
| | | public class MelsecMcDataType { |
| | | |
| | | |
| | | /** |
| | | * 如果您清楚类型代号,可以根据值进行扩展 |
| | | * @param code 数据类型的代号 |
| | | * @param type 0或1,默认为0 |
| | | * @param asciiCode ASCII格式的类型信息 |
| | | * @param fromBase 指示地址的多少进制的,10或是16 |
| | | */ |
| | | public MelsecMcDataType( byte code, byte type, String asciiCode, int fromBase ) |
| | | { |
| | | DataCode = code; |
| | | AsciiCode = asciiCode; |
| | | FromBase = fromBase; |
| | | if (type < 2) DataType = type; |
| | | } |
| | | |
| | | |
| | | |
| | | private byte DataCode = 0x00; // 类型代号 |
| | | private byte DataType = 0x00; // 数据类型 |
| | | private String AsciiCode = ""; // ascii格式通信的字符 |
| | | private int FromBase = 0; // 类型 |
| | | |
| | | |
| | | /** |
| | | * 数据的类型代号 |
| | | * @return |
| | | */ |
| | | public byte getDataCode() { |
| | | return DataCode; |
| | | } |
| | | |
| | | /** |
| | | * 字访问还是位访问,0表示字,1表示位 |
| | | * @return |
| | | */ |
| | | public byte getDataType() { |
| | | return DataType; |
| | | } |
| | | |
| | | /** |
| | | * 当以ASCII格式通讯时的类型描述 |
| | | * @return |
| | | */ |
| | | public String getAsciiCode() { |
| | | return AsciiCode; |
| | | } |
| | | |
| | | /** |
| | | * 指示地址是10进制,还是16进制的 |
| | | * @return |
| | | */ |
| | | public int getFromBase() { |
| | | return FromBase; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * X输入寄存器 |
| | | */ |
| | | public final static MelsecMcDataType X = new MelsecMcDataType( (byte) (0x9C), (byte) (0x01), "X*", 16 ); |
| | | /** |
| | | * Y输出寄存器 |
| | | */ |
| | | public final static MelsecMcDataType Y = new MelsecMcDataType( (byte) (0x9D), (byte) (0x01), "Y*", 16 ); |
| | | /** |
| | | * M中间寄存器 |
| | | */ |
| | | public final static MelsecMcDataType M = new MelsecMcDataType( (byte) (0x90), (byte) (0x01), "M*", 10 ); |
| | | /** |
| | | * D数据寄存器 |
| | | */ |
| | | public final static MelsecMcDataType D = new MelsecMcDataType( (byte) (0xA8), (byte) (0x00), "D*", 10 ); |
| | | /** |
| | | * W链接寄存器 |
| | | */ |
| | | public final static MelsecMcDataType W = new MelsecMcDataType( (byte) (0xB4), (byte) (0x00), "W*", 16 ); |
| | | /** |
| | | * L锁存继电器 |
| | | */ |
| | | public final static MelsecMcDataType L = new MelsecMcDataType( (byte) (0x92), (byte) (0x01), "L*", 10 ); |
| | | /** |
| | | * F报警器 |
| | | */ |
| | | public final static MelsecMcDataType F = new MelsecMcDataType( (byte) (0x93), (byte) (0x01), "F*", 10 ); |
| | | /** |
| | | * V边沿继电器 |
| | | */ |
| | | public final static MelsecMcDataType V = new MelsecMcDataType( (byte) (0x94), (byte) (0x01), "V*", 10 ); |
| | | /** |
| | | * B链接继电器 |
| | | */ |
| | | public final static MelsecMcDataType B = new MelsecMcDataType( (byte) (0xA0), (byte) (0x01), "B*", 16 ); |
| | | /** |
| | | * R文件寄存器 |
| | | */ |
| | | public final static MelsecMcDataType R = new MelsecMcDataType( (byte) (0xAF), (byte) (0x00), "R*", 10 ); |
| | | /** |
| | | * S步进继电器 |
| | | */ |
| | | public final static MelsecMcDataType S = new MelsecMcDataType( (byte) (0x98), (byte) (0x01), "S*", 10 ); |
| | | /** |
| | | * 变址寄存器 |
| | | */ |
| | | public final static MelsecMcDataType Z = new MelsecMcDataType( (byte) (0xCC), (byte) (0x00), "Z*", 10 ); |
| | | /** |
| | | * 定时器的值 |
| | | */ |
| | | public final static MelsecMcDataType T = new MelsecMcDataType( (byte) (0xC2), (byte) (0x00), "TN", 10 ); |
| | | /** |
| | | * 计数器的值 |
| | | */ |
| | | public final static MelsecMcDataType C = new MelsecMcDataType( (byte) (0xC5), (byte) (0x00), "CN", 10 ); |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Melsec; |
| | | |
| | | import com.zy.common.HslCommunication.Core.IMessage.MelsecQnA3EBinaryMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.RegularByteTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | /** |
| | | * 三菱的实际数据交互类 |
| | | */ |
| | | public class MelsecMcNet extends NetworkDeviceBase<MelsecQnA3EBinaryMessage,RegularByteTransform> { |
| | | |
| | | |
| | | /** |
| | | * 实例化三菱的Qna兼容3E帧协议的通讯对象 |
| | | */ |
| | | public MelsecMcNet() { |
| | | WordLength = 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个三菱的Qna兼容3E帧协议的通讯对象 |
| | | * |
| | | * @param ipAddress PLCd的Ip地址 |
| | | * @param port PLC的端口 |
| | | */ |
| | | public MelsecMcNet(String ipAddress, int port) { |
| | | WordLength = 1; |
| | | super.setIpAddress(ipAddress); |
| | | super.setPort(port); |
| | | } |
| | | |
| | | |
| | | private byte NetworkNumber = 0x00; // 网络号 |
| | | private byte NetworkStationNumber = 0x00; // 网络站号 |
| | | |
| | | /** |
| | | * 获取网络号 |
| | | * |
| | | * @return 网络号 |
| | | */ |
| | | public byte getNetworkNumber() { |
| | | return NetworkNumber; |
| | | } |
| | | |
| | | /** |
| | | * 设置网络号 |
| | | * |
| | | * @param networkNumber 网络号 |
| | | */ |
| | | public void setNetworkNumber(byte networkNumber) { |
| | | NetworkNumber = networkNumber; |
| | | } |
| | | |
| | | /** |
| | | * 获取网络站号 |
| | | * |
| | | * @return 网络站号 |
| | | */ |
| | | public byte getNetworkStationNumber() { |
| | | return NetworkStationNumber; |
| | | } |
| | | |
| | | /** |
| | | * 设置网络站号 |
| | | * |
| | | * @param networkStationNumber 网络站号 |
| | | */ |
| | | public void setNetworkStationNumber(byte networkStationNumber) { |
| | | NetworkStationNumber = networkStationNumber; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中读取想要的数据,返回读取结果 |
| | | * @param address 读取地址,格式为"M100","D100","W1A0" |
| | | * @param length 读取的数据长度,字最大值960,位最大值7168 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | @Override |
| | | public OperateResultExOne<byte[]> Read(String address, short length) { |
| | | // 获取指令 |
| | | OperateResultExOne<byte[]> command = BuildReadCommand( address, length, NetworkNumber, NetworkStationNumber ); |
| | | if (!command.IsSuccess) return OperateResultExOne.CreateFailedResult( command ); |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult( read ); |
| | | |
| | | // 错误代码验证 |
| | | int errorCode = Utilities.getShort(read.Content, 9); |
| | | if (errorCode != 0) return new OperateResultExOne<>( errorCode, StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 数据解析,需要传入是否使用位的参数 |
| | | return ExtractActualData( read.Content, command.Content[13] == 1 ); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @param length 读取的长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadBool(String address, short length) { |
| | | // 解析地址 |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress( address ); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult( analysis ); |
| | | |
| | | // 位读取校验 |
| | | if (analysis.Content1.getDataType() == 0x00) return new OperateResultExOne<boolean[]>( 0, StringResources.Language.MelsecReadBitInfo() ); |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = Read( address, length ); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult( read ); |
| | | |
| | | // 转化bool数组 |
| | | boolean[] result = new boolean[read.Content.length]; |
| | | for(int i=0;i<result.length;i++){ |
| | | if(read.Content[i] == 0x01) result[i] = true; |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult( result ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从三菱PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 起始地址 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadBool(String address) { |
| | | OperateResultExOne<boolean[]> read = ReadBool(address, (short) 1); |
| | | if (!read.IsSuccess) return OperateResultExOne.CreateFailedResult(read); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(read.Content[0]); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC写入数据,数据格式为原始的字节类型 |
| | | * @param address 起始地址 |
| | | * @param value 原始数据 |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | public OperateResult Write(String address, byte[] value) { |
| | | // 解析指令 |
| | | OperateResultExOne<byte[]> command = BuildWriteCommand( address, value, NetworkNumber, NetworkStationNumber ); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer( command.Content ); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 错误码校验 |
| | | short ErrorCode = Utilities.getShort(read.Content, 9); |
| | | if (ErrorCode != 0) return new OperateResultExOne<byte[]>( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument() ); |
| | | |
| | | // 成功 |
| | | return OperateResult.CreateSuccessResult( ); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param value 要写入的实际数据,长度为8的倍数 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean value) { |
| | | return Write(address, new boolean[]{value}); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100 |
| | | * @param address 要写入的数据地址 |
| | | * @param values 要写入的实际数据,可以指定任意的长度 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean[] values) { |
| | | byte[] buffer = new byte[values.length]; |
| | | for (int i = 0; i < values.length; i++) { |
| | | buffer[i] = values[i] ? (byte) 0x01 : (byte) 0x00; |
| | | } |
| | | return Write(address, buffer); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取当前对象的字符串标识形式 |
| | | * @return 字符串信息 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "MelsecMcNet"; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildReadCommand(String address, short length) { |
| | | return BuildReadCommand(address,length,(byte) 0,(byte)0); |
| | | } |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @param networkNumber 网络号 |
| | | * @param networkStationNumber 网络站号 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildReadCommand(String address, short length, byte networkNumber, byte networkStationNumber) { |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | byte[] _PLCCommand = new byte[21]; |
| | | _PLCCommand[0] = 0x50; // 副标题 |
| | | _PLCCommand[1] = 0x00; |
| | | _PLCCommand[2] = networkNumber; // 网络号 |
| | | _PLCCommand[3] = (byte) (0xFF); // PLC编号 |
| | | _PLCCommand[4] = (byte) (0xFF); |
| | | _PLCCommand[5] = 0x03; |
| | | _PLCCommand[6] = networkStationNumber; // 目标模块站号 |
| | | _PLCCommand[7] = 0x0C; // 请求数据长度 |
| | | _PLCCommand[8] = 0x00; |
| | | _PLCCommand[9] = 0x0A; // CPU监视定时器 |
| | | _PLCCommand[10] = 0x00; |
| | | _PLCCommand[11] = 0x01; // 批量读取数据命令 |
| | | _PLCCommand[12] = 0x04; |
| | | _PLCCommand[13] = analysis.Content1.getDataType(); // 以点为单位还是字为单位成批读取 |
| | | _PLCCommand[14] = 0x00; |
| | | _PLCCommand[15] = (byte) (analysis.Content2 % 256); // 起始地址的地位 |
| | | _PLCCommand[16] = (byte) (analysis.Content2 / 256); |
| | | _PLCCommand[17] = 0x00; |
| | | _PLCCommand[18] = analysis.Content1.getDataCode(); // 指明读取的数据 |
| | | _PLCCommand[19] = (byte) (length % 256); // 软元件长度的地位 |
| | | _PLCCommand[20] = (byte) (length / 256); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(_PLCCommand); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param address 起始地址 |
| | | * @param value 值 |
| | | * @return 结果 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value) { |
| | | return BuildWriteCommand(address,value,(byte)0,(byte)0); |
| | | } |
| | | |
| | | /** |
| | | * 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param address 起始地址 |
| | | * @param value 值 |
| | | * @param networkNumber 网络号 |
| | | * @param networkStationNumber 网络站号 |
| | | * @return 结果 |
| | | */ |
| | | public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value, byte networkNumber, byte networkStationNumber) { |
| | | OperateResultExTwo<MelsecMcDataType, Short> analysis = MelsecHelper.McAnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.CreateFailedResult(analysis); |
| | | |
| | | int length = -1; |
| | | if (analysis.Content1.getDataType() == 1) |
| | | { |
| | | // 按照位写入的操作,数据需要重新计算 |
| | | length = value.length; |
| | | value = MelsecHelper.TransBoolArrayToByteData( value ); |
| | | } |
| | | |
| | | byte[] _PLCCommand = new byte[21 + value.length]; |
| | | _PLCCommand[0] = 0x50; // 副标题 |
| | | _PLCCommand[1] = 0x00; |
| | | _PLCCommand[2] = networkNumber; // 网络号 |
| | | _PLCCommand[3] = (byte) (0xFF); // PLC编号 |
| | | _PLCCommand[4] = (byte) (0xFF); // 目标模块IO编号 |
| | | _PLCCommand[5] = 0x03; |
| | | _PLCCommand[6] = networkStationNumber; // 目标模块站号 |
| | | |
| | | _PLCCommand[7] = (byte) ((_PLCCommand.length - 9) % 256); // 请求数据长度 |
| | | _PLCCommand[8] = (byte) ((_PLCCommand.length - 9) / 256); |
| | | ; |
| | | _PLCCommand[9] = 0x0A; // CPU监视定时器 |
| | | _PLCCommand[10] = 0x00; |
| | | _PLCCommand[11] = 0x01; // 批量读取数据命令 |
| | | _PLCCommand[12] = 0x14; |
| | | _PLCCommand[13] = analysis.Content1.getDataType(); // 以点为单位还是字为单位成批读取 |
| | | _PLCCommand[14] = 0x00; |
| | | _PLCCommand[15] = (byte) (analysis.Content2 % 256); |
| | | ; // 起始地址的地位 |
| | | _PLCCommand[16] = (byte) (analysis.Content2 / 256); |
| | | _PLCCommand[17] = 0x00; |
| | | _PLCCommand[18] = analysis.Content1.getDataCode(); // 指明写入的数据 |
| | | |
| | | // 判断是否进行位操作 |
| | | if (analysis.Content1.getDataType() == 1) { |
| | | if (length > 0) { |
| | | _PLCCommand[19] = (byte) (length % 256); // 软元件长度的地位 |
| | | _PLCCommand[20] = (byte) (length / 256); |
| | | } else { |
| | | _PLCCommand[19] = (byte) (value.length * 2 % 256); // 软元件长度的地位 |
| | | _PLCCommand[20] = (byte) (value.length * 2 / 256); |
| | | } |
| | | } else { |
| | | _PLCCommand[19] = (byte) (value.length / 2 % 256); // 软元件长度的地位 |
| | | _PLCCommand[20] = (byte) (value.length / 2 / 256); |
| | | } |
| | | |
| | | System.arraycopy(value, 0, _PLCCommand, 21, value.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult(_PLCCommand); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取 |
| | | * @param response 反馈的数据内容 |
| | | * @param isBit 是否位读取 |
| | | * @return 解析后的结果对象 |
| | | */ |
| | | public static OperateResultExOne<byte[]> ExtractActualData( byte[] response, boolean isBit ) |
| | | { |
| | | if (isBit) |
| | | { |
| | | // 位读取 |
| | | byte[] Content = new byte[(response.length - 11) * 2]; |
| | | for (int i = 11; i < response.length; i++) |
| | | { |
| | | if ((response[i] & 0x10) == 0x10) |
| | | { |
| | | Content[(i - 11) * 2 + 0] = 0x01; |
| | | } |
| | | |
| | | if ((response[i] & 0x01) == 0x01) |
| | | { |
| | | Content[(i - 11) * 2 + 1] = 0x01; |
| | | } |
| | | } |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | else |
| | | { |
| | | // 字读取 |
| | | byte[] Content = new byte[response.length - 11]; |
| | | System.arraycopy(response,11,Content,0,Content.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( Content ); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Omron; |
| | | |
| | | /** |
| | | * 欧姆龙的Fins协议的数据类型 |
| | | */ |
| | | public class OmronFinsDataType |
| | | { |
| | | /** |
| | | * 实例化一个Fins的数据类型 |
| | | * @param bitCode 位操作的指令 |
| | | * @param wordCode 字操作的指令 |
| | | */ |
| | | public OmronFinsDataType( byte bitCode, byte wordCode ) |
| | | { |
| | | BitCode = bitCode; |
| | | WordCode = wordCode; |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 获取进行位操作的指令 |
| | | * @return |
| | | */ |
| | | public byte getBitCode() { |
| | | return BitCode; |
| | | } |
| | | |
| | | /** |
| | | * 进行字操作的指令 |
| | | * @return |
| | | */ |
| | | public byte getWordCode() { |
| | | return WordCode; |
| | | } |
| | | |
| | | |
| | | private byte BitCode = 0; |
| | | private byte WordCode = 0; |
| | | |
| | | |
| | | |
| | | /** |
| | | * DM Area |
| | | */ |
| | | public static final OmronFinsDataType DM = new OmronFinsDataType( (byte) 0x02, (byte) 0x82 ); |
| | | |
| | | /** |
| | | * CIO Area |
| | | */ |
| | | public static final OmronFinsDataType CIO = new OmronFinsDataType( (byte)0x30, (byte)0xB0 ); |
| | | |
| | | /** |
| | | * Work Area |
| | | */ |
| | | public static final OmronFinsDataType WR = new OmronFinsDataType( (byte)0x31, (byte)0xB1 ); |
| | | |
| | | /** |
| | | * Holding Bit Area |
| | | */ |
| | | public static final OmronFinsDataType HR = new OmronFinsDataType( (byte)0x32, (byte)0xB2 ); |
| | | |
| | | /** |
| | | * Auxiliary Bit Area |
| | | */ |
| | | public static final OmronFinsDataType AR = new OmronFinsDataType( (byte)0x33, (byte)0xB3 ); |
| | | } |
New file |
| | |
| | | package com.zy.common.HslCommunication.Profinet.Omron; |
| | | |
| | | import com.zy.common.HslCommunication.Core.IMessage.FinsMessage; |
| | | import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase; |
| | | import com.zy.common.HslCommunication.Core.Transfer.ReverseWordTransform; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.net.Socket; |
| | | |
| | | /** |
| | | * 欧姆龙Fins帧协议通讯类 |
| | | */ |
| | | public class OmronFinsNet extends NetworkDeviceBase<FinsMessage,ReverseWordTransform> { |
| | | /** |
| | | * 实例化一个欧姆龙Fins帧协议的通讯对象 |
| | | */ |
| | | public OmronFinsNet() { |
| | | WordLength = 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 实例化一个欧姆龙Fins帧协议的通讯对象 |
| | | * @param ipAddress PLCd的Ip地址 |
| | | * @param port PLC的端口 |
| | | */ |
| | | public OmronFinsNet(String ipAddress, int port) { |
| | | WordLength = 1; |
| | | setIpAddress(ipAddress); |
| | | setPort(port); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 信息控制字段,默认0x80 |
| | | */ |
| | | public byte ICF = (byte) 0x80; |
| | | |
| | | /** |
| | | * 系统使用的内部信息 |
| | | */ |
| | | public byte RSV = 0x00; |
| | | |
| | | /** |
| | | * 网络层信息,默认0x02,如果有八层消息,就设置为0x07 |
| | | */ |
| | | public byte GCT = 0x02; |
| | | |
| | | /** |
| | | * PLC的网络号地址,默认0x00 |
| | | */ |
| | | public byte DNA = 0x00; |
| | | |
| | | |
| | | /** |
| | | * PLC的节点地址,默认0x13 |
| | | */ |
| | | public byte DA1 = 0x13; |
| | | |
| | | /** |
| | | * PLC的单元号地址 |
| | | */ |
| | | public byte DA2 = 0x00; |
| | | |
| | | /** |
| | | * 上位机的网络号地址 |
| | | */ |
| | | public byte SNA = 0x00; |
| | | |
| | | |
| | | private byte computerSA1 = 0x0B; |
| | | |
| | | /** |
| | | * 上位机的节点地址,默认0x0B |
| | | * |
| | | * @return byte数据 |
| | | */ |
| | | public byte getSA1() { |
| | | return computerSA1; |
| | | } |
| | | |
| | | /** |
| | | * 设置上位机的节点地址,默认0x0B |
| | | * |
| | | * @param computerSA1 |
| | | */ |
| | | public void setSA1(byte computerSA1) { |
| | | this.computerSA1 = computerSA1; |
| | | handSingle[19] = computerSA1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 上位机的单元号地址 |
| | | */ |
| | | public byte SA2 = 0x00; |
| | | |
| | | /** |
| | | * 设备的标识号 |
| | | */ |
| | | public byte SID = 0x00; |
| | | |
| | | |
| | | |
| | | /** |
| | | * 将普通的指令打包成完整的指令 |
| | | * @param cmd 指令 |
| | | * @return 字节 |
| | | */ |
| | | private byte[] PackCommand(byte[] cmd) { |
| | | byte[] buffer = new byte[26 + cmd.length]; |
| | | System.arraycopy(handSingle, 0, buffer, 0, 4); |
| | | |
| | | byte[] tmp = Utilities.getBytes(buffer.length - 8); |
| | | Utilities.bytesReverse(tmp); // 翻转数组 |
| | | |
| | | System.arraycopy(tmp, 0, buffer, 4, tmp.length); |
| | | buffer[11] = 0x02; |
| | | |
| | | buffer[16] = ICF; |
| | | buffer[17] = RSV; |
| | | buffer[18] = GCT; |
| | | buffer[19] = DNA; |
| | | buffer[20] = DA1; |
| | | buffer[21] = DA2; |
| | | buffer[22] = SNA; |
| | | buffer[23] = getSA1(); |
| | | buffer[24] = SA2; |
| | | buffer[25] = SID; |
| | | System.arraycopy(cmd, 0, buffer, 26, cmd.length); |
| | | |
| | | return buffer; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据类型地址长度确认需要读取的指令头 |
| | | * @param address 起始地址 |
| | | * @param length 长度 |
| | | * @param isBit 是否是位读取 |
| | | * @return 带有成功标志的指令数据 |
| | | */ |
| | | private OperateResultExOne<byte[]> BuildReadCommand(String address, int length, boolean isBit) { |
| | | OperateResultExTwo<OmronFinsDataType, byte[]> analysis = AnalysisAddress(address, isBit); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | byte[] _PLCCommand = new byte[8]; |
| | | _PLCCommand[0] = 0x01; |
| | | _PLCCommand[1] = 0x01; |
| | | if (isBit) { |
| | | _PLCCommand[2] = analysis.Content1.getBitCode(); |
| | | } else { |
| | | _PLCCommand[2] = analysis.Content1.getWordCode(); |
| | | } |
| | | |
| | | System.arraycopy(analysis.Content2, 0, _PLCCommand, 3, analysis.Content2.length); |
| | | _PLCCommand[6] = (byte) (length / 256); |
| | | _PLCCommand[7] = (byte) (length % 256); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( PackCommand( _PLCCommand ) ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * |
| | | * @param address 根据类型地址以及需要写入的数据来生成指令头 |
| | | * @param value 起始地址 |
| | | * @param isBit 是否是位操作 |
| | | * @return 结果 |
| | | */ |
| | | private OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] value, boolean isBit) { |
| | | OperateResultExTwo<OmronFinsDataType, byte[]> analysis = AnalysisAddress(address, isBit); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis); |
| | | |
| | | byte[] _PLCCommand = new byte[8 + value.length]; |
| | | _PLCCommand[0] = 0x01; // 读取存储区数据 |
| | | _PLCCommand[1] = 0x02; |
| | | if (isBit) { |
| | | _PLCCommand[2] = analysis.Content1.getBitCode(); |
| | | } else { |
| | | _PLCCommand[2] = analysis.Content1.getWordCode(); |
| | | } |
| | | |
| | | System.arraycopy(analysis.Content2, 0, _PLCCommand, 3, analysis.Content2.length); |
| | | |
| | | if (isBit) { |
| | | _PLCCommand[6] = (byte) (value.length / 256); |
| | | _PLCCommand[7] = (byte) (value.length % 256); |
| | | } else { |
| | | _PLCCommand[6] = (byte) (value.length / 2 / 256); |
| | | _PLCCommand[7] = (byte) (value.length / 2 % 256); |
| | | } |
| | | |
| | | System.arraycopy(value, 0, _PLCCommand, 8, value.length); |
| | | |
| | | return OperateResultExOne.CreateSuccessResult( PackCommand( _PLCCommand ) ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 在连接上欧姆龙PLC后,需要进行一步握手协议 |
| | | * @param socket 网络套接字 |
| | | * @return 结果对象 |
| | | */ |
| | | @Override |
| | | protected OperateResult InitializationOnConnect(Socket socket) { |
| | | // handSingle就是握手信号字节 |
| | | OperateResultExTwo<byte[], byte[]> read = ReadFromCoreServerBase(socket, handSingle); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 检查返回的状态 |
| | | byte[] buffer = new byte[4]; |
| | | buffer[0] = read.Content2[7]; |
| | | buffer[1] = read.Content2[6]; |
| | | buffer[2] = read.Content2[5]; |
| | | buffer[3] = read.Content2[4]; |
| | | int status = Utilities.getInt(buffer, 0); |
| | | if (status != 0) return new OperateResult( status, GetStatusDescription( status ) ); |
| | | |
| | | // 提取PLC的节点地址 |
| | | if (read.Content2.length >= 16) DA1 = read.Content2[15]; |
| | | |
| | | return OperateResult.CreateSuccessResult(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从欧姆龙PLC中读取想要的数据,返回读取结果,读取单位为字 |
| | | * @param address 读取地址,格式为"D100","C100","W100","H100","A100" |
| | | * @param length 读取的数据长度,字最大值960,位最大值7168 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | @Override |
| | | public OperateResultExOne<byte[]> Read(String address, short length) { |
| | | //获取指令 |
| | | OperateResultExOne<byte[]> command = BuildReadCommand(address, length, false); |
| | | if (!command.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(command); |
| | | |
| | | // 核心数据交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer(command.Content); |
| | | if (!read.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(read); |
| | | |
| | | // 数据有效性分析 |
| | | OperateResultExOne<byte[]> valid = ResponseValidAnalysis(read.Content, true); |
| | | if (!valid.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(valid); |
| | | |
| | | // 读取到了正确的数据 |
| | | return OperateResultExOne.CreateSuccessResult(valid.Content); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从欧姆龙PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 读取地址,格式为"D100","C100","W100","H100","A100" |
| | | * @param length 读取的长度 |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<boolean[]> ReadBool(String address, short length) { |
| | | //获取指令 |
| | | OperateResultExOne<byte[]> command = BuildReadCommand(address, length, true); |
| | | if (!command.IsSuccess) return OperateResultExOne.<boolean[]>CreateFailedResult(command); |
| | | |
| | | // 核心数据交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer(command.Content); |
| | | if (!read.IsSuccess) return OperateResultExOne.<boolean[]>CreateFailedResult(read); |
| | | |
| | | // 数据有效性分析 |
| | | OperateResultExOne<byte[]> valid = ResponseValidAnalysis(read.Content, true); |
| | | if (!valid.IsSuccess) return OperateResultExOne.<boolean[]>CreateFailedResult(valid); |
| | | |
| | | // 返回正确的数据信息 |
| | | boolean[] buffer = new boolean[valid.Content.length]; |
| | | for (int i = 0; i < valid.Content.length; i++) { |
| | | buffer[i] = valid.Content[i] != 0x00; |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 从欧姆龙PLC中批量读取位软元件,返回读取结果 |
| | | * @param address 读取地址,格式为"D100.0","C100.15","W100.7","H100.4","A100.9" |
| | | * @return 带成功标志的结果数据对象 |
| | | */ |
| | | public OperateResultExOne<Boolean> ReadBool(String address) { |
| | | OperateResultExOne<boolean[]> read = ReadBool(address, (short) 1); |
| | | if (read.IsSuccess) { |
| | | return OperateResultExOne.CreateSuccessResult(read.Content[0]); |
| | | } else { |
| | | return OperateResultExOne.<Boolean>CreateFailedResult(read); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 向PLC写入数据,数据格式为原始的字节类型 |
| | | * @param address 起始地址 |
| | | * @param value 原始数据 |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | public OperateResult Write(String address, byte[] value) { |
| | | //获取指令 |
| | | OperateResultExOne<byte[]> command = BuildWriteCommand(address, value, false); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心数据交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer(command.Content); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 数据有效性分析 |
| | | OperateResultExOne<byte[]> valid = ResponseValidAnalysis(read.Content, false); |
| | | if (!valid.IsSuccess) return valid; |
| | | |
| | | // 成功 |
| | | return OperateResult.CreateSuccessResult(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0 |
| | | * @param address 要写入的数据地址 |
| | | * @param value 要写入的实际数据,长度为8的倍数 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean value) { |
| | | return Write(address, new boolean[]{value}); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0 |
| | | * @param address 要写入的数据地址 |
| | | * @param values 要写入的实际数据,可以指定任意的长度 |
| | | * @return 返回写入结果 |
| | | */ |
| | | public OperateResult Write(String address, boolean[] values) { |
| | | OperateResult result = new OperateResult(); |
| | | |
| | | byte[] buffer = new byte[values.length]; |
| | | for (int i = 0; i < buffer.length; i++) { |
| | | buffer[i] = values[i] ? (byte) 0x01 : (byte) 0x00; |
| | | } |
| | | |
| | | // 获取指令 |
| | | OperateResultExOne<byte[]> command = BuildWriteCommand(address, buffer, true); |
| | | if (!command.IsSuccess) return command; |
| | | |
| | | // 核心数据交互 |
| | | OperateResultExOne<byte[]> read = ReadFromCoreServer(command.Content); |
| | | if (!read.IsSuccess) return read; |
| | | |
| | | // 数据有效性分析 |
| | | OperateResultExOne<byte[]> valid = ResponseValidAnalysis(read.Content, false); |
| | | if (!valid.IsSuccess) return valid; |
| | | |
| | | // 写入成功 |
| | | return OperateResult.CreateSuccessResult(); |
| | | } |
| | | |
| | | |
| | | // 握手信号 |
| | | // 46494E530000000C0000000000000000000000D6 |
| | | private final byte[] handSingle = new byte[] |
| | | { |
| | | 0x46, 0x49, 0x4E, 0x53, // FINS |
| | | 0x00, 0x00, 0x00, 0x0C, // 后面的命令长度 |
| | | 0x00, 0x00, 0x00, 0x00, // 命令码 |
| | | 0x00, 0x00, 0x00, 0x00, // 错误码 |
| | | 0x00, 0x00, 0x00, 0x01 // 节点号 |
| | | }; |
| | | |
| | | |
| | | /** |
| | | * 返回表示当前对象的字符串 |
| | | * |
| | | * @return 字符串 |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | return "OmronFinsNet"; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 解析数据地址,Omron手册第188页 |
| | | * @param address 数据地址 |
| | | * @param isBit 是否是位地址 |
| | | * @return 结果类对象 |
| | | */ |
| | | public static OperateResultExTwo<OmronFinsDataType, byte[]> AnalysisAddress(String address, boolean isBit) { |
| | | OperateResultExTwo<OmronFinsDataType, byte[]> result = new OperateResultExTwo<OmronFinsDataType, byte[]>(); |
| | | try { |
| | | switch (address.charAt(0)) { |
| | | case 'D': |
| | | case 'd': { |
| | | // DM区数据 |
| | | result.Content1 = OmronFinsDataType.DM; |
| | | break; |
| | | } |
| | | case 'C': |
| | | case 'c': { |
| | | // CIO区数据 |
| | | result.Content1 = OmronFinsDataType.CIO; |
| | | break; |
| | | } |
| | | case 'W': |
| | | case 'w': { |
| | | // WR区 |
| | | result.Content1 = OmronFinsDataType.WR; |
| | | break; |
| | | } |
| | | case 'H': |
| | | case 'h': { |
| | | // HR区 |
| | | result.Content1 = OmronFinsDataType.HR; |
| | | break; |
| | | } |
| | | case 'A': |
| | | case 'a': { |
| | | // AR区 |
| | | result.Content1 = OmronFinsDataType.AR; |
| | | break; |
| | | } |
| | | default: |
| | | throw new Exception(StringResources.Language.NotSupportedDataType()); |
| | | } |
| | | |
| | | if (isBit) { |
| | | // 位操作 |
| | | String[] splits = address.substring(1).split("\\."); |
| | | int addr = Integer.parseInt(splits[0]); |
| | | result.Content2 = new byte[3]; |
| | | result.Content2[0] = Utilities.getBytes(addr)[1]; |
| | | result.Content2[1] = Utilities.getBytes(addr)[0]; |
| | | |
| | | if (splits.length > 1) { |
| | | result.Content2[2] = Byte.parseByte(splits[1]); |
| | | if (result.Content2[2] > 15) { |
| | | throw new Exception(StringResources.Language.OmronAddressMustBeZeroToFiveteen()); |
| | | } |
| | | } |
| | | } else { |
| | | // 字操作 |
| | | int addr = Integer.parseInt(address.substring(1)); |
| | | result.Content2 = new byte[3]; |
| | | result.Content2[0] = Utilities.getBytes(addr)[1]; |
| | | result.Content2[1] = Utilities.getBytes(addr)[0]; |
| | | } |
| | | } catch (Exception ex) { |
| | | result.Message = ex.getMessage(); |
| | | return result; |
| | | } |
| | | |
| | | result.IsSuccess = true; |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 对于PLC的反馈数据,进行验证 |
| | | * @param response PLC反馈数据 |
| | | * @param isRead 是否处于读取状态 |
| | | * @return 成功的数据结果 |
| | | */ |
| | | public static OperateResultExOne<byte[]> ResponseValidAnalysis(byte[] response, boolean isRead) { |
| | | // 数据有效性分析 |
| | | if (response.length >= 16) { |
| | | // 提取错误码 |
| | | byte[] buffer = new byte[4]; |
| | | buffer[0] = response[15]; |
| | | buffer[1] = response[14]; |
| | | buffer[2] = response[13]; |
| | | buffer[3] = response[12]; |
| | | |
| | | int err = Utilities.getInt(buffer, 0); |
| | | if (err > 0) return new OperateResultExOne<byte[]>(err, GetStatusDescription(err)); |
| | | |
| | | if (response.length >= 30) { |
| | | err = response[28] * 256 + response[29]; |
| | | if (err > 0) return new OperateResultExOne<byte[]>(err,StringResources.Language.OmronReceiveDataError()); |
| | | |
| | | if (!isRead) { |
| | | // 写入操作 |
| | | return OperateResultExOne.CreateSuccessResult(new byte[0]); |
| | | } else { |
| | | // 读取操作 |
| | | byte[] content = new byte[response.length - 30]; |
| | | if (content.length > 0) { |
| | | System.arraycopy(response, 30, content, 0, content.length); |
| | | } |
| | | return OperateResultExOne.CreateSuccessResult(content); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return new OperateResultExOne<byte[]>( StringResources.Language.OmronReceiveDataError() ); |
| | | } |
| | | |
| | | /** |
| | | * 获取错误信息的字符串描述文本 |
| | | * @param err 错误码 |
| | | * @return 文本描述 |
| | | */ |
| | | public static String GetStatusDescription( int err ) |
| | | { |
| | | switch (err) |
| | | { |
| | | case 0: return StringResources.Language.OmronStatus0(); |
| | | case 1: return StringResources.Language.OmronStatus1(); |
| | | case 2: return StringResources.Language.OmronStatus2(); |
| | | case 3: return StringResources.Language.OmronStatus3(); |
| | | case 20: return StringResources.Language.OmronStatus20(); |
| | | case 21: return StringResources.Language.OmronStatus21(); |
| | | case 22: return StringResources.Language.OmronStatus22(); |
| | | case 23: return StringResources.Language.OmronStatus23(); |
| | | case 24: return StringResources.Language.OmronStatus24(); |
| | | case 25: return StringResources.Language.OmronStatus25(); |
| | | default: return StringResources.Language.UnknownError(); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | 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<FetchWriteMessage, ReverseBytesTransform> { |
| | | |
| | | /** |
| | | * 实例化一个西门子的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<byte[]> Read(String address, short length) { |
| | | OperateResultExOne<byte[]> result = new OperateResultExOne<byte[]>(); |
| | | OperateResultExOne<byte[]> command = BuildReadCommand(address, length); |
| | | if (!command.IsSuccess) { |
| | | result.CopyErrorFromOther(command); |
| | | return result; |
| | | } |
| | | |
| | | OperateResultExOne<byte[]> 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<Byte> 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<byte[]> command = BuildWriteCommand(address, value); |
| | | if (!command.IsSuccess) { |
| | | result.CopyErrorFromOther(command); |
| | | return result; |
| | | } |
| | | |
| | | |
| | | OperateResultExOne<byte[]> 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<Byte, Integer, Integer> AnalysisAddress(String address) { |
| | | OperateResultExThree<Byte, Integer, Integer> result = new OperateResultExThree<Byte, Integer, Integer>(); |
| | | 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<Byte, Integer, Integer>(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<byte[]> BuildReadCommand(String address, int count) { |
| | | OperateResultExThree<Byte, Integer, Integer> analysis = AnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>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<byte[]>(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<byte[]> BuildWriteCommand(String address, byte[] data) { |
| | | if (data == null) data = new byte[0]; |
| | | OperateResultExThree<Byte, Integer, Integer> analysis = AnalysisAddress(address); |
| | | if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>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<byte[]>(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.<byte[]>CreateSuccessResult(_PLCCommand); |
| | | } |
| | | |
| | | } |
File was renamed from src/main/java/com/zy/gateway/core/domain/siemens/SiemensPLCS.java |
| | |
| | | package com.zy.gateway.core.domain.siemens; |
| | | package com.zy.common.HslCommunication.Profinet.Siemens; |
| | | |
| | | /** |
| | | * 西门子的PLC类型,目前支持的访问类型 |
File was renamed from src/main/java/com/zy/gateway/core/net/siemens/SiemensS7Net.java |
| | |
| | | package com.zy.gateway.core.net.siemens; |
| | | package com.zy.common.HslCommunication.Profinet.Siemens; |
| | | |
| | | import com.zy.gateway.core.StringResources; |
| | | import com.zy.gateway.core.base.SoftBasic; |
| | | import com.zy.gateway.core.domain.OperateResult; |
| | | import com.zy.gateway.core.domain.OperateResultExOne; |
| | | import com.zy.gateway.core.domain.OperateResultExThree; |
| | | import com.zy.gateway.core.domain.OperateResultExTwo; |
| | | import com.zy.gateway.core.domain.siemens.S7Message; |
| | | import com.zy.gateway.core.domain.siemens.SiemensPLCS; |
| | | import com.zy.gateway.core.net.NetworkDeviceBase; |
| | | import com.zy.gateway.core.transfer.ReverseBytesTransform; |
| | | import com.zy.gateway.core.utils.Utilities; |
| | | import com.zy.common.HslCommunication.BasicFramework.SoftBasic; |
| | | import com.zy.common.HslCommunication.Core.IMessage.S7Message; |
| | | 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.Core.Types.OperateResultExTwo; |
| | | import com.zy.common.HslCommunication.StringResources; |
| | | import com.zy.common.HslCommunication.Utilities; |
| | | |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.net.Socket; |
| | |
| | | return OperateResultExOne.CreateSuccessResult(buffer); |
| | | } |
| | | else { |
| | | return new OperateResultExOne<byte[]>(read.ErrorCode, StringResources.Language.SiemensDataLengthCheckFailed()); |
| | | return new OperateResultExOne<byte[]>(read.ErrorCode,StringResources.Language.SiemensDataLengthCheckFailed()); |
| | | } |
| | | } |
| | | |
File was renamed from src/main/java/com/zy/gateway/core/utils/Utilities.java |
| | |
| | | package com.zy.gateway.core.utils; |
| | | package com.zy.common.HslCommunication; |
| | | |
| | | |
| | | import java.io.ByteArrayOutputStream; |
New file |
| | |
| | | package com.zy.common; |
| | | |
| | | import com.zy.common.HslCommunication.Core.Net.NetHandle; |
| | | import com.zy.common.HslCommunication.Core.Transfer.DataFormat; |
| | | import com.zy.common.HslCommunication.Core.Types.ActionOperateExThree; |
| | | import com.zy.common.HslCommunication.Core.Types.ActionOperateExTwo; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResult; |
| | | import com.zy.common.HslCommunication.Core.Types.OperateResultExOne; |
| | | import com.zy.common.HslCommunication.Enthernet.ComplexNet.NetComplexClient; |
| | | import com.zy.common.HslCommunication.Enthernet.PushNet.NetPushClient; |
| | | import com.zy.common.HslCommunication.Enthernet.SimplifyNet.NetSimplifyClient; |
| | | import com.zy.common.HslCommunication.ModBus.ModbusTcpNet; |
| | | import com.zy.common.HslCommunication.Profinet.Melsec.MelsecA1ENet; |
| | | import com.zy.common.HslCommunication.Profinet.Melsec.MelsecMcAsciiNet; |
| | | import com.zy.common.HslCommunication.Profinet.Melsec.MelsecMcNet; |
| | | import com.zy.common.HslCommunication.Profinet.Siemens.SiemensPLCS; |
| | | import com.zy.common.HslCommunication.Profinet.Siemens.SiemensS7Net; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | public class Main { |
| | | |
| | | public static void main(String[] args) throws InterruptedException { |
| | | SiemesTest(); |
| | | try { |
| | | //Constructor[] aa = Integer.class.getDeclaredConstructors(); |
| | | //int i = (Integer) (aa[1].newInstance("1")); |
| | | //System.out.println(Utilities.bytes2HexString( Utilities.getBytes(String.format("%04x",100),"ASCII"))); |
| | | //System.out.println(i); |
| | | |
| | | //System.out.println(Arrays.toString("123".split("\\." ))); |
| | | //ModbusTcpTets(); |
| | | //MelsecMcNet melsec_net = new MelsecMcNet("192.168.8.12", 6001); |
| | | //System.out.println(melsec_net.ReadInt16("D100").Content); |
| | | |
| | | SiemensS7Net siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200,"192.168.8.12"); |
| | | OperateResult write = siemensS7Net.Write("M200",(short)200); |
| | | |
| | | if(!write.IsSuccess){ |
| | | System.out.println("Write failed:"+write.Message); |
| | | } |
| | | |
| | | OperateResultExOne<Short> read = siemensS7Net.ReadInt16("M200"); |
| | | if(read.IsSuccess){ |
| | | System.out.println("Value:"+read.Content.toString()); |
| | | } |
| | | else { |
| | | System.out.println("Read failed:"+read.Message); |
| | | } |
| | | } |
| | | catch (Exception ex){ |
| | | System.out.println(ex.getMessage()); |
| | | } |
| | | Thread.sleep(1000); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 简单网络客户端 |
| | | */ |
| | | public static void NetSimplifyClientTest() { |
| | | NetSimplifyClient client = new NetSimplifyClient("127.0.0.1", 12345); |
| | | OperateResultExOne<String> read = client.ReadFromServer(new NetHandle(2), "测试数据"); |
| | | if (read.IsSuccess) { |
| | | System.out.println(read.Content); |
| | | } else { |
| | | System.out.println("读取失败:" + read.Message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 三菱 A |
| | | */ |
| | | private static void MelsecA1ETest() { |
| | | MelsecA1ENet melsec_net = new MelsecA1ENet("192.168.0.100", 5000); |
| | | melsec_net.SetPersistentConnection(); |
| | | |
| | | boolean[] M100 = melsec_net.ReadBool("M100", (short) 1).Content; // 读取M100是否通,十进制地址 |
| | | boolean[] X20 = melsec_net.ReadBool("X20", (short) 1).Content; // 读取X20是否通,八进制地址 |
| | | boolean[] Y20 = melsec_net.ReadBool("Y20", (short) 1).Content; // 读取Y20是否通,八进制地址 |
| | | short short_D1000 = melsec_net.ReadInt16("D1000").Content; // 读取D1000的short值 |
| | | int int_D1000 = melsec_net.ReadInt32("D1000").Content; // 读取D1000-D1001组成的int数据 |
| | | float float_D1000 = melsec_net.ReadFloat("D1000").Content; // 读取D1000-D1001组成的float数据 |
| | | long long_D1000 = melsec_net.ReadInt64("D1000").Content; // 读取D1000-D1003组成的long数据 |
| | | double double_D1000 = melsec_net.ReadDouble("D1000").Content; // 读取D1000-D1003组成的double数据 |
| | | String str_D1000 = melsec_net.ReadString("D1000", (short) 10).Content; // 读取D1000-D1009组成的条码数据 |
| | | |
| | | |
| | | melsec_net.Write("M100", new boolean[]{true}); // 写入M100为通 |
| | | melsec_net.Write("Y20", new boolean[]{true}); // 写入Y20为通 |
| | | melsec_net.Write("X20", new boolean[]{true}); // 写入X20为通 |
| | | melsec_net.Write("D1000", (short) 1234); // 写入D1000 short值 ,W3C0,R3C0 效果是一样的 |
| | | melsec_net.Write("D1000", 1234566); // 写入D1000 int值 |
| | | melsec_net.Write("D1000", 123.456f); // 写入D1000 float值 |
| | | melsec_net.Write("D1000", 123.456d); // 写入D1000 double值 |
| | | melsec_net.Write("D1000", 123456661235123534L); // 写入D1000 long值 |
| | | melsec_net.Write("D1000", "K123456789"); // 写入D1000 string值 |
| | | |
| | | |
| | | OperateResultExOne<boolean[]> read = melsec_net.ReadBool("M100", (short) 10); |
| | | if (read.IsSuccess) { |
| | | boolean m100 = read.Content[0]; |
| | | boolean m101 = read.Content[1]; |
| | | boolean m102 = read.Content[2]; |
| | | boolean m103 = read.Content[3]; |
| | | boolean m104 = read.Content[4]; |
| | | boolean m105 = read.Content[5]; |
| | | boolean m106 = read.Content[6]; |
| | | boolean m107 = read.Content[7]; |
| | | boolean m108 = read.Content[8]; |
| | | boolean m109 = read.Content[9]; |
| | | } else { |
| | | System.out.print("读取失败:" + read.Message); |
| | | } |
| | | |
| | | |
| | | OperateResultExOne<byte[]> read1 = melsec_net.Read("D100", (short) 5); |
| | | if (read1.IsSuccess) { |
| | | short D100 = melsec_net.getByteTransform().TransInt16(read1.Content, 0); |
| | | short D101 = melsec_net.getByteTransform().TransInt16(read1.Content, 2); |
| | | short D102 = melsec_net.getByteTransform().TransInt16(read1.Content, 4); |
| | | short D103 = melsec_net.getByteTransform().TransInt16(read1.Content, 6); |
| | | short D104 = melsec_net.getByteTransform().TransInt16(read1.Content, 8); |
| | | } else { |
| | | System.out.print("读取失败:" + read1.Message); |
| | | } |
| | | |
| | | |
| | | //解析复杂数据 |
| | | OperateResultExOne<byte[]> read3 = melsec_net.Read("D4000", (short) 10); |
| | | if (read3.IsSuccess) { |
| | | double 温度 = melsec_net.getByteTransform().TransInt16(read3.Content, 0) / 10d;//索引很重要 |
| | | double 压力 = melsec_net.getByteTransform().TransInt16(read3.Content, 2) / 100d; |
| | | boolean IsRun = melsec_net.getByteTransform().TransInt16(read3.Content, 4) == 1; |
| | | int 产量 = melsec_net.getByteTransform().TransInt32(read3.Content, 6); |
| | | String 规格 = melsec_net.getByteTransform().TransString(read3.Content, 10, 10, "ascii"); |
| | | } else { |
| | | System.out.print("读取失败:" + read3.Message); |
| | | } |
| | | |
| | | // 写入测试,M100-M104 写入测试 此处写入后M100:通 M101:断 M102:断 M103:通 M104:通 |
| | | boolean[] values = new boolean[]{true, false, false, true, true}; |
| | | OperateResult write = melsec_net.Write("M100", values); |
| | | if (write.IsSuccess) { |
| | | System.out.print("写入成功"); |
| | | } else { |
| | | System.out.print("写入失败:" + write.Message); |
| | | } |
| | | |
| | | |
| | | OperateResultExOne<Boolean> read2 = melsec_net.ReadBool("M100"); |
| | | if (read2.IsSuccess) { |
| | | System.out.println(read2.Content); |
| | | } else { |
| | | System.out.println("读取失败:" + read.Message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 三菱 Q |
| | | */ |
| | | private static void MelsecTest() { |
| | | MelsecMcNet melsec_net = new MelsecMcNet("192.168.1.192", 6001); |
| | | |
| | | |
| | | boolean[] M100 = melsec_net.ReadBool("M100", (short) 1).Content; // 读取M100是否通,十进制地址 |
| | | boolean[] X1A0 = melsec_net.ReadBool("X1A0", (short) 1).Content; // 读取X1A0是否通,十六进制地址 |
| | | boolean[] Y1A0 = melsec_net.ReadBool("Y1A0", (short) 1).Content; // 读取Y1A0是否通,十六进制地址 |
| | | boolean[] B1A0 = melsec_net.ReadBool("B1A0", (short) 1).Content; // 读取B1A0是否通,十六进制地址 |
| | | short short_D1000 = melsec_net.ReadInt16("D1000").Content; // 读取D1000的short值 ,W3C0,R3C0 效果是一样的 |
| | | int int_D1000 = melsec_net.ReadInt32("D1000").Content; // 读取D1000-D1001组成的int数据 |
| | | float float_D1000 = melsec_net.ReadFloat("D1000").Content; // 读取D1000-D1001组成的float数据 |
| | | long long_D1000 = melsec_net.ReadInt64("D1000").Content; // 读取D1000-D1003组成的long数据 |
| | | double double_D1000 = melsec_net.ReadDouble("D1000").Content; // 读取D1000-D1003组成的double数据 |
| | | String str_D1000 = melsec_net.ReadString("D1000", (short) 10).Content; // 读取D1000-D1009组成的条码数据 |
| | | |
| | | |
| | | melsec_net.Write("M100", new boolean[]{true}); // 写入M100为通 |
| | | melsec_net.Write("Y1A0", new boolean[]{true}); // 写入Y1A0为通 |
| | | melsec_net.Write("X1A0", new boolean[]{true}); // 写入X1A0为通 |
| | | melsec_net.Write("B1A0", new boolean[]{true}); // 写入B1A0为通 |
| | | melsec_net.Write("D1000", (short) 1234); // 写入D1000 short值 ,W3C0,R3C0 效果是一样的 |
| | | melsec_net.Write("D1000", 1234566); // 写入D1000 int值 |
| | | melsec_net.Write("D1000", 123.456f); // 写入D1000 float值 |
| | | melsec_net.Write("D1000", 123.456d); // 写入D1000 double值 |
| | | melsec_net.Write("D1000", 123456661235123534L); // 写入D1000 long值 |
| | | melsec_net.Write("D1000", "K123456789"); // 写入D1000 string值 |
| | | |
| | | |
| | | OperateResultExOne<boolean[]> read = melsec_net.ReadBool("M100", (short) 10); |
| | | if (read.IsSuccess) { |
| | | boolean m100 = read.Content[0]; |
| | | boolean m101 = read.Content[1]; |
| | | boolean m102 = read.Content[2]; |
| | | boolean m103 = read.Content[3]; |
| | | boolean m104 = read.Content[4]; |
| | | boolean m105 = read.Content[5]; |
| | | boolean m106 = read.Content[6]; |
| | | boolean m107 = read.Content[7]; |
| | | boolean m108 = read.Content[8]; |
| | | boolean m109 = read.Content[9]; |
| | | } else { |
| | | System.out.print("读取失败:" + read.Message); |
| | | } |
| | | |
| | | |
| | | OperateResultExOne<byte[]> read1 = melsec_net.Read("D100", (short) 5); |
| | | if (read1.IsSuccess) { |
| | | short D100 = melsec_net.getByteTransform().TransByte(read1.Content, 0); |
| | | short D101 = melsec_net.getByteTransform().TransByte(read1.Content, 2); |
| | | short D102 = melsec_net.getByteTransform().TransByte(read1.Content, 4); |
| | | short D103 = melsec_net.getByteTransform().TransByte(read1.Content, 6); |
| | | short D104 = melsec_net.getByteTransform().TransByte(read1.Content, 8); |
| | | } else { |
| | | System.out.print("读取失败:" + read1.Message); |
| | | } |
| | | |
| | | |
| | | //解析复杂数据 |
| | | OperateResultExOne<byte[]> read3 = melsec_net.Read("D4000", (short) 10); |
| | | if (read3.IsSuccess) { |
| | | double 温度 = melsec_net.getByteTransform().TransInt16(read3.Content, 0) / 10d;//索引很重要 |
| | | double 压力 = melsec_net.getByteTransform().TransInt16(read3.Content, 2) / 100d; |
| | | boolean IsRun = melsec_net.getByteTransform().TransInt16(read3.Content, 4) == 1; |
| | | int 产量 = melsec_net.getByteTransform().TransInt32(read3.Content, 6); |
| | | String 规格 = melsec_net.getByteTransform().TransString(read3.Content, 10, 10, "ascii"); |
| | | } else { |
| | | System.out.print("读取失败:" + read3.Message); |
| | | } |
| | | |
| | | // 写入测试,M100-M104 写入测试 此处写入后M100:通 M101:断 M102:断 M103:通 M104:通 |
| | | boolean[] values = new boolean[]{true, false, false, true, true}; |
| | | OperateResult write = melsec_net.Write("M100", values); |
| | | if (write.IsSuccess) { |
| | | System.out.print("写入成功"); |
| | | } else { |
| | | System.out.print("写入失败:" + write.Message); |
| | | } |
| | | |
| | | |
| | | OperateResultExOne<Boolean> read2 = melsec_net.ReadBool("M100"); |
| | | if (read2.IsSuccess) { |
| | | System.out.println(read2.Content); |
| | | } else { |
| | | System.out.println("读取失败:" + read.Message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 三菱 Q ASCII通讯格式 |
| | | */ |
| | | private static void MelsecAsciiTest(){ |
| | | |
| | | MelsecMcAsciiNet melsec = new MelsecMcAsciiNet("192.168.1.192",6001); |
| | | OperateResultExOne<short[]> read = melsec.ReadInt16("D100",(short) 2); |
| | | if(read.IsSuccess) |
| | | { |
| | | System.out.println(Arrays.toString(read.Content)); |
| | | } |
| | | else { |
| | | System.out.println(read.ToMessageShowString()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 四门子 |
| | | */ |
| | | private static void SiemesTest(){ |
| | | SiemensS7Net siemens_net = new SiemensS7Net(SiemensPLCS.S1200,"192.168.1.195"); |
| | | OperateResult connect = siemens_net.ConnectServer(); |
| | | if(connect.IsSuccess){ |
| | | System.out.println("connect success!"); |
| | | } |
| | | else { |
| | | System.out.println("failed:"+connect.Message); |
| | | } |
| | | siemens_net.ConnectClose(); |
| | | |
| | | // 上面是初始化 |
| | | System.out.println(siemens_net.ReadByte("M100").Content); |
| | | |
| | | byte m100_byte = siemens_net.ReadByte("M100").Content; |
| | | short m100_short = siemens_net.ReadInt16("M100").Content; |
| | | int m100_int = siemens_net.ReadInt32("M100").Content; |
| | | long m100_long = siemens_net.ReadInt64("M100").Content; |
| | | float m100_float = siemens_net.ReadFloat("M100").Content; |
| | | double m100_double = siemens_net.ReadDouble("M100").Content; |
| | | String m100_string = siemens_net.ReadString("M100",(short) 10).Content; |
| | | |
| | | siemens_net.Write("M100",(byte) 123); |
| | | siemens_net.Write("M100",(short) 123); |
| | | siemens_net.Write("M100",(int) 123); |
| | | siemens_net.Write("M100",(long) 123); |
| | | siemens_net.Write("M100", 123.456f); |
| | | siemens_net.Write("M100", 123.456d); |
| | | siemens_net.Write("M100","1234567890"); |
| | | |
| | | OperateResultExOne<byte[]> read = siemens_net.Read( "M100", (short) 10 ); |
| | | { |
| | | if(read.IsSuccess) |
| | | { |
| | | byte m100 = read.Content[0]; |
| | | byte m101 = read.Content[1]; |
| | | byte m102 = read.Content[2]; |
| | | byte m103 = read.Content[3]; |
| | | byte m104 = read.Content[4]; |
| | | byte m105 = read.Content[5]; |
| | | byte m106 = read.Content[6]; |
| | | byte m107 = read.Content[7]; |
| | | byte m108 = read.Content[8]; |
| | | byte m109 = read.Content[9]; |
| | | } |
| | | else |
| | | { |
| | | // 发生了异常 |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | private static void PushNetTest() { |
| | | NetPushClient client = new NetPushClient("127.0.0.1", 23467, "A"); |
| | | OperateResult connect = client.CreatePush(new ActionOperateExTwo<NetPushClient,String>(){ |
| | | @Override |
| | | public void Action(NetPushClient content1, String content2) { |
| | | System.out.println(content2); |
| | | } |
| | | }); |
| | | if (connect.IsSuccess) { |
| | | System.out.println("连接成功!"); |
| | | } else { |
| | | System.out.println("连接失败!"+connect.Message); |
| | | } |
| | | } |
| | | |
| | | private static void ModbusTcpTets(){ |
| | | ModbusTcpNet modbusTcpNet = new ModbusTcpNet("127.0.0.1",502,(byte) 0x01); |
| | | // 当你需要指定格式的数据解析时,就需要设置下面的这个信息 |
| | | modbusTcpNet.setDataFormat(DataFormat.BADC); |
| | | OperateResultExOne<Double> read = modbusTcpNet.ReadDouble("s=2;x=4;200"); |
| | | if(read.IsSuccess){ |
| | | System.out.println(read.Content); |
| | | } |
| | | else { |
| | | System.out.println(read.Message); |
| | | } |
| | | |
| | | modbusTcpNet.Write("100",new int[]{12345,-12345}); |
| | | } |
| | | |
| | | private static void NetComplexClientTest(){ |
| | | System.out.println("Hello World!等待10s关闭"); |
| | | NetComplexClient client = new NetComplexClient(); |
| | | client.setIpAddress("127.0.0.1"); |
| | | client.setPort(12346); |
| | | client.setClientAlias("测试1"); |
| | | client.AcceptString= new ActionOperateExThree<NetComplexClient,NetHandle,String>(){ |
| | | @Override |
| | | public void Action(NetComplexClient content1, NetHandle content2, String content3) { |
| | | System.out.println("Handle:"+content2.get_CodeValue()+" Value:"+content3); |
| | | } |
| | | }; |
| | | |
| | | |
| | | client.ClientStart(); |
| | | |
| | | // client.Send(new NetHandle(1),"asdasdi阿斯达阿斯达"); |
| | | // System.out.println(client.getDelayTime()); |
| | | // Thread.sleep(100000); |
| | | // client.ClientClose(); |
| | | |
| | | |
| | | } |
| | | |
| | | } |
| | |
| | | if (user.getStatus()!=1){ |
| | | return R.parse(CodeRes.USER_10002); |
| | | } |
| | | if (!Cools.md5(user.getPassword()).equals(password)){ |
| | | if (!user.getPassword().equals(password)){ |
| | | return R.parse(CodeRes.USER_10003); |
| | | } |
| | | String token = Cools.enToken(System.currentTimeMillis() + mobile, user.getPassword()); |
| | |
| | | # password: xltys1995 |
| | | # sql-server |
| | | driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver |
| | | url: jdbc:sqlserver://127.0.0.1:1433;databasename=dlasrs |
| | | url: jdbc:sqlserver://127.0.0.1:1433;databasename=jsasrs |
| | | username: sa |
| | | password: sa@123 |
| | | mvc: |
| | |
| | | // var baseUrl = "/wcs"; |
| | | // 测试 |
| | | var baseUrl = ""; |
| | | // 系统运行状态 |
| | | var systemRunning = true; |
| | | |
| | | |
| | | // 赋值 |
| | | function setVal(el, val) { |
| | |
| | | |
| | | // 系统运行开关 |
| | | function systemSwitch() { |
| | | if (systemRunning){ |
| | | if (parent.systemRunning){ |
| | | layer.prompt({title: '请输入口令,并停止 WCS 系统', formType: 1, shadeClose: true}, function(pass, idx){ |
| | | layer.close(idx); |
| | | doSwitch(0, pass); // 停止wcs系统 |
| | |
| | | if (res.data.status) { |
| | | $('#system-icon').attr("class", "system-icon-open"); |
| | | $('#system-run-desc').html("系统运行中..."); |
| | | systemRunning = true; |
| | | parent.systemRunning = true; |
| | | } else { |
| | | $('#system-icon').attr("class", "system-icon-close"); |
| | | $('#system-run-desc').html("系统已停止!"); |
| | | systemRunning = false; |
| | | parent.systemRunning = false; |
| | | } |
| | | } else if (res.code === 403){ |
| | | window.location.href = baseUrl+"/login"; |
| | |
| | | if (res.data.status) { |
| | | $('#system-icon').attr("class", "system-icon-open"); |
| | | $('#system-run-desc').html("系统运行中..."); |
| | | systemRunning = true; |
| | | parent.systemRunning = true; |
| | | } else { |
| | | $('#system-icon').attr("class", "system-icon-close"); |
| | | $('#system-run-desc').html("系统已停止!"); |
| | | systemRunning = false; |
| | | parent.systemRunning = false; |
| | | } |
| | | } else if (res.code === 403){ |
| | | window.location.href = baseUrl+"/login"; |
| | |
| | | |
| | | // 判断手动操作模块是否可用 |
| | | function operatorBlockShow() { |
| | | if (systemRunning) { |
| | | if (parent.systemRunning) { |
| | | $('.crn-operation').css("opacity", "0.5"); |
| | | $('.crn-operation-shade').show(); |
| | | $('.crn-operation-shade-span').show(); |
| | |
| | | localStorage.removeItem("token"); |
| | | window.location.href = baseUrl + "/login"; |
| | | } |
| | | |
| | | // 系统运行状态 |
| | | var systemRunning = true; |
| | | </script> |
| | | </html> |
| | | |