diff --git a/NA200H/ModBus.Net/AddressTranslator.cs b/NA200H/ModBus.Net/AddressTranslator.cs index 8bc98aa..23aeb9e 100644 --- a/NA200H/ModBus.Net/AddressTranslator.cs +++ b/NA200H/ModBus.Net/AddressTranslator.cs @@ -2,6 +2,9 @@ namespace ModBus.Net { + /// + /// 数据单元翻译器 + /// public abstract class AddressTranslator { protected static AddressTranslator _instance; @@ -10,6 +13,9 @@ namespace ModBus.Net public abstract ushort AddressTranslate(string address); } + /// + /// NA200H数据单元翻译器 + /// public class AddressTranslatorNA200H : AddressTranslator { private AddressTranslatorNA200H() diff --git a/NA200H/ModBus.Net/BaseProtocal.cs b/NA200H/ModBus.Net/BaseProtocal.cs index bf9d574..d1f2232 100644 --- a/NA200H/ModBus.Net/BaseProtocal.cs +++ b/NA200H/ModBus.Net/BaseProtocal.cs @@ -4,10 +4,13 @@ using System.Reflection; namespace ModBus.Net { + /// + /// 基本协议 + /// public abstract class BaseProtocal { /// - /// 发送数据 + /// 发送数据 /// /// 需要发送的数据 /// 数据是否正确接收 @@ -18,6 +21,11 @@ namespace ModBus.Net Protocals = new Dictionary(); } + /// + /// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议 + /// + /// 协议的类的名称 + /// public ProtocalUnit this[string protocalName] { get @@ -26,6 +34,7 @@ namespace ModBus.Net { return Protocals[protocalName]; } + //自动寻找存在的协议并将其加载 var protocalUnit = Assembly.Load("ModBus.Net").CreateInstance("ModBus.Net." + protocalName) as ProtocalUnit; if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容"); @@ -36,24 +45,29 @@ namespace ModBus.Net protected Dictionary Protocals { get; private set; } - public void Register(ProtocalUnit linkProtocal) + protected void Register(ProtocalUnit linkProtocal) { if (linkProtocal == null) return; Protocals.Add(linkProtocal.GetType().Name, linkProtocal); } + /// + /// 发送协议内容并接收,一般方法 + /// + /// + /// public virtual byte[] SendReceive(params object[] content) { int t; return _protocalLinker.SendReceive(ProtocalUnit.TranslateContent(content)); } - public virtual OutputStruct SendReceive(ProtocalUnit unit, params object[] content) - { - int t = 0; - return unit.Unformat(_protocalLinker.SendReceive(unit.Format(content)), ref t); - } - + /// + /// 发送协议,通过传入需要使用的协议内容和输入结构 + /// + /// + /// + /// public virtual OutputStruct SendReceive(ProtocalUnit unit, InputStruct content) { int t = 0; @@ -61,14 +75,22 @@ namespace ModBus.Net } /// - /// 接收数据 + /// 仅发送数据 /// - /// 接收到的数据 + /// + /// + /// public virtual bool SendOnly(ProtocalUnit unit, params object[] content) { return _protocalLinker.SendOnly(unit.Format(content)); } + /// + /// 仅发送数据 + /// + /// + /// + /// public virtual bool SendOnly(ProtocalUnit unit, InputStruct content) { return _protocalLinker.SendOnly(unit.Format(content)); diff --git a/NA200H/ModBus.Net/IProtocalFormatting.cs b/NA200H/ModBus.Net/IProtocalFormatting.cs index 39b190e..14c995d 100644 --- a/NA200H/ModBus.Net/IProtocalFormatting.cs +++ b/NA200H/ModBus.Net/IProtocalFormatting.cs @@ -1,11 +1,30 @@ namespace ModBus.Net { + /// + /// 协议转换的接口 + /// public interface IProtocalFormatting { + /// + /// 从输入结构格式化 + /// + /// + /// byte[] Format(InputStruct message); + /// + /// 从对象的参数数组格式化 + /// + /// + /// byte[] Format(params object[] message); + /// + /// 把仪器返回的内容填充到输出结构中 + /// + /// + /// + /// OutputStruct Unformat(byte[] messageBytes, ref int pos); } } \ No newline at end of file diff --git a/NA200H/ModBus.Net/ModBus.Net.csproj b/NA200H/ModBus.Net/ModBus.Net.csproj index 9585270..d67e0f3 100644 --- a/NA200H/ModBus.Net/ModBus.Net.csproj +++ b/NA200H/ModBus.Net/ModBus.Net.csproj @@ -49,7 +49,9 @@ ConfigurationManager.resx + + diff --git a/NA200H/ModBus.Net/ModbusProtocal.cs b/NA200H/ModBus.Net/ModbusProtocal.cs index 28ac1a8..58b5bda 100644 --- a/NA200H/ModBus.Net/ModbusProtocal.cs +++ b/NA200H/ModBus.Net/ModbusProtocal.cs @@ -23,6 +23,9 @@ namespace ModBus.Net } + /// + /// 读线圈状态 + /// public class ReadCoilStatusModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -91,6 +94,9 @@ namespace ModBus.Net } } + /// + /// 读输入状态协 + /// public class ReadInputStatusModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -161,6 +167,9 @@ namespace ModBus.Net } } + /// + /// 读保持型寄存器 + /// public class ReadHoldRegisterModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -224,6 +233,9 @@ namespace ModBus.Net } } + /// + /// 读输入型寄存器 + /// public class ReadInputRegisterModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -347,6 +359,9 @@ namespace ModBus.Net } } + /// + /// 读单个线圈状态 + /// public class WriteOneCoilModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -406,6 +421,9 @@ namespace ModBus.Net } } + /// + /// 写单个寄存器状态 + /// public class WriteOneRegisterModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -463,6 +481,9 @@ namespace ModBus.Net } } + /// + /// 写多个线圈状态 + /// public class WriteMultiCoilModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -537,6 +558,9 @@ namespace ModBus.Net } } + /// + /// 写多个寄存器状态 + /// public class WriteMultiRegisterModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -602,6 +626,9 @@ namespace ModBus.Net } } + /// + /// 读系统时间 + /// public class GetSystemTimeModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) @@ -668,6 +695,9 @@ namespace ModBus.Net } } + /// + /// 写系统时间 + /// public class SetSystemTimeModbusProtocal : ProtocalUnit { public override byte[] Format(InputStruct message) diff --git a/NA200H/ModBus.Net/ModbusTCPProtocal.cs b/NA200H/ModBus.Net/ModbusTCPProtocal.cs index aebf866..238e88b 100644 --- a/NA200H/ModBus.Net/ModbusTCPProtocal.cs +++ b/NA200H/ModBus.Net/ModbusTCPProtocal.cs @@ -2,11 +2,15 @@ namespace ModBus.Net { + /// + /// Modbus/Tcp协议 + /// public class ModbusTcpProtocal : ModbusProtocal { + //将连接器设置为Tcp连接器 public ModbusTcpProtocal() { - _protocalLinker = new TcpProtocalLinker(); + _protocalLinker = new ModbusTcpProtocalLinker(); } } } \ No newline at end of file diff --git a/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs b/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs new file mode 100644 index 0000000..a0cca7a --- /dev/null +++ b/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net +{ + class ModbusTcpProtocalLinker : TcpProtocalLinker + { + public override bool CheckRight(byte[] content) + { + if (content[1] > 127) + { + throw new ModbusProtocalErrorException(content[2]); + } + return true; + } + } +} diff --git a/NA200H/ModBus.Net/ProtocalLinker.cs b/NA200H/ModBus.Net/ProtocalLinker.cs index 0ac5b5b..2c6f107 100644 --- a/NA200H/ModBus.Net/ProtocalLinker.cs +++ b/NA200H/ModBus.Net/ProtocalLinker.cs @@ -2,22 +2,54 @@ namespace ModBus.Net { + /// + /// 基本的协议连接器 + /// public abstract class ProtocalLinker { + /// + /// 发送并接收数据 + /// + /// 发送协议的内容 + /// 接收协议的内容 public abstract byte[] SendReceive(byte[] content); + /// + /// 仅发送数据 + /// + /// 发送协议的内容 + /// 协议是否正确发送 public abstract bool SendOnly(byte[] content); + /// + /// 检查接收的数据是否正确 + /// + /// 接收协议的内容 + /// 协议是否是正确的 + public abstract bool CheckRight(byte[] content); + + /// + /// 协议内容扩展,发送时根据需要扩展 + /// + /// 扩展前的基本协议内容 + /// 扩展后的协议内容 public byte[] BytesExtend(byte[] content) { + //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 ProtocalLinkerBytesExtend bytesExtend = Assembly.Load("ModBus.Net").CreateInstance(this.GetType().FullName + "BytesExtend") as ProtocalLinkerBytesExtend; return bytesExtend.BytesExtend(content); } + /// + /// 协议内容缩减,接收时根据需要缩减 + /// + /// 缩减前的完整协议内容 + /// 缩减后的协议内容 public byte[] BytesDecact(byte[] content) { + //自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。 ProtocalLinkerBytesExtend bytesExtend = Assembly.Load("ModBus.Net").CreateInstance(this.GetType().FullName + "BytesExtend") as ProtocalLinkerBytesExtend; diff --git a/NA200H/ModBus.Net/ProtocalLinkerBytesExtend.cs b/NA200H/ModBus.Net/ProtocalLinkerBytesExtend.cs new file mode 100644 index 0000000..508537f --- /dev/null +++ b/NA200H/ModBus.Net/ProtocalLinkerBytesExtend.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net +{ + /// + /// 协议字节伸缩 + /// + public abstract class ProtocalLinkerBytesExtend + { + /// + /// 协议扩展,协议内容发送前调用 + /// + /// 扩展前的原始协议内容 + /// 扩展后的协议内容 + public abstract byte[] BytesExtend(byte[] content); + + /// + /// 协议收缩,协议内容接收后调用 + /// + /// 收缩前的完整协议内容 + /// 收缩后的协议内容 + public abstract byte[] BytesDecact(byte[] content); + } + + /// + /// Tcp协议字节伸缩 + /// + public class ModbusTcpProtocalLinkerBytesExtend : ProtocalLinkerBytesExtend + { + public override byte[] BytesExtend(byte[] content) + { + //Modbus/Tcp协议扩张,前面加6个字节,前面4个为0,后面两个为协议整体内容的长度 + byte[] newFormat = new byte[6 + content.Length]; + int tag = 0; + ushort leng = (ushort)content.Length; + Array.Copy(ValueHelper.Instance.GetBytes(tag), 0, newFormat, 0, 4); + Array.Copy(ValueHelper.Instance.GetBytes(leng), 0, newFormat, 4, 2); + Array.Copy(content, 0, newFormat, 6, content.Length); + return newFormat; + } + + public override byte[] BytesDecact(byte[] content) + { + //Modbus/Tcp协议收缩,抛弃前面6个字节的内容 + byte[] newContent = new byte[content.Length - 6]; + Array.Copy(content, 6, newContent, 0, newContent.Length); + return newContent; + } + } +} diff --git a/NA200H/ModBus.Net/ProtocalUnit.cs b/NA200H/ModBus.Net/ProtocalUnit.cs index f000898..1b2f31d 100644 --- a/NA200H/ModBus.Net/ProtocalUnit.cs +++ b/NA200H/ModBus.Net/ProtocalUnit.cs @@ -7,21 +7,40 @@ namespace ModBus.Net { public abstract class ProtocalUnit : IProtocalFormatting { + /// + /// 格式化,将输入结构转换为字节数组 + /// + /// + /// public abstract byte[] Format(InputStruct message); + /// + /// 格式化,将对象数组转换为字节数组 + /// + /// + /// public virtual byte[] Format(params object[] message) { return TranslateContent(message); } - public abstract OutputStruct Unformat(byte[] messageBytes, ref int pos); /// + /// 结构化,将字节数组转换为输出结构。 + /// + /// + /// + /// + public abstract OutputStruct Unformat(byte[] messageBytes, ref int pos); + + /// + /// 转换静态方法,把对象数组转换为字节数组。 /// /// /// public static byte[] TranslateContent(params object[] contents) { bool b = false; + //先查找传入的结构中有没有数组,有的话将其打开 var newContentsList = new List(); foreach (object content in contents) { @@ -38,7 +57,9 @@ namespace ModBus.Net newContentsList.Add(content); } } + //重新调用一边这个函数,这个传入的参数中一定没有数组。 if (b) return TranslateContent(newContentsList.ToArray()); + //把参数一个一个翻译为相对应的字节,然后拼成一个队列 var translateTarget = new List(); foreach (object content in contents) { @@ -96,14 +117,21 @@ namespace ModBus.Net } } } + //最后把队列转换为数组 return translateTarget.ToArray(); } } + /// + /// 输入结构 + /// public class InputStruct { } + /// + /// 输出结构 + /// public class OutputStruct { } diff --git a/NA200H/ModBus.Net/TCPProtocalLinker.cs b/NA200H/ModBus.Net/TCPProtocalLinker.cs index 088469d..ead8bcf 100644 --- a/NA200H/ModBus.Net/TCPProtocalLinker.cs +++ b/NA200H/ModBus.Net/TCPProtocalLinker.cs @@ -4,61 +4,37 @@ using System.Linq; namespace ModBus.Net { - public class TcpProtocalLinker : ProtocalLinker + public abstract class TcpProtocalLinker : ProtocalLinker { + /// + /// 连接对象 + /// private TcpSocket _socket; - - - public TcpProtocalLinker() + + protected TcpProtocalLinker() { + //初始化连对象 _socket = new TcpSocket(ConfigurationManager.IP, int.Parse(ConfigurationManager.Port), false); } public override byte[] SendReceive(byte[] content) { + //接收数据 byte[] receiveBytes = BytesDecact(_socket.SendMsg(BytesExtend(content))); - if (receiveBytes[1] > 127) - { - string message; - throw new ModbusProtocalErrorException(receiveBytes[2]); - } + //容错处理 + if (!CheckRight(content)) return null; + //返回数据 return receiveBytes; } + public override bool SendOnly(byte[] content) { return _socket.SendMsgWithoutReturn(BytesExtend(content)); } } - - public abstract class ProtocalLinkerBytesExtend - { - public abstract byte[] BytesExtend(byte[] content); - - public abstract byte[] BytesDecact(byte[] content); - } - - public class TcpProtocalLinkerBytesExtend : ProtocalLinkerBytesExtend - { - public override byte[] BytesExtend(byte[] content) - { - byte[] newFormat = new byte[6 + content.Length]; - int tag = 0; - ushort leng = (ushort)content.Length; - Array.Copy(ValueHelper.Instance.GetBytes(tag), 0, newFormat, 0, 4); - Array.Copy(ValueHelper.Instance.GetBytes(leng), 0, newFormat, 4, 2); - Array.Copy(content, 0, newFormat, 6, content.Length); - return newFormat; - } - - public override byte[] BytesDecact(byte[] content) - { - byte[] newContent = new byte[content.Length - 6]; - Array.Copy(content, 6, newContent, 0, newContent.Length); - return newContent; - } - } + public class ProtocalErrorException : Exception { diff --git a/NA200H/ModBus.Net/TCPSocket.cs b/NA200H/ModBus.Net/TCPSocket.cs index ed1af6d..3cf96ab 100644 --- a/NA200H/ModBus.Net/TCPSocket.cs +++ b/NA200H/ModBus.Net/TCPSocket.cs @@ -31,7 +31,7 @@ namespace ModBus.Net private readonly string host; // 2MB 的接收缓冲区,目的是一次接收完服务器发回的消息 - private readonly byte[] m_receiveBuffer = new byte[200000]; + private readonly byte[] m_receiveBuffer = new byte[1024]; private readonly int port; public int m_errorCount = 0; public int m_receiveCount = 0; diff --git a/NA200H/ModBus.Net/ValueHelper.cs b/NA200H/ModBus.Net/ValueHelper.cs index b855d3c..207e865 100644 --- a/NA200H/ModBus.Net/ValueHelper.cs +++ b/NA200H/ModBus.Net/ValueHelper.cs @@ -2,20 +2,29 @@ namespace ModBus.Net { + /// + /// 值与字节数组之间转换的辅助类,这是一个Singleton类 + /// 作者:罗圣(Chris L.) + /// public class ValueHelper { + protected static bool _littleEndian = false; protected ValueHelper() { } + /// + /// 协议中的内容构造是否小端的,默认是大端构造协议。 + /// public static bool LittleEndian { get { return _littleEndian; } set { _littleEndian = value; + //这里需要重点说明,因为.net默认是小端构造法,所以目标协议是大端的话反而需要调用小端构造协议,把小端反转为大端。 _Instance = LittleEndian ? new ValueHelper() : new LittleEndianValueHelper(); } } diff --git a/NA200H/NA200H.UI.Console/Program.cs b/NA200H/NA200H.UI.Console/Program.cs index 258b6cc..b3d275b 100644 --- a/NA200H/NA200H.UI.Console/Program.cs +++ b/NA200H/NA200H.UI.Console/Program.cs @@ -12,10 +12,15 @@ namespace NA200H.UI.ConsoleApp { static void Main(string[] args) { + //先初始化一个协议转换器,这里构造Modbus/Tcp协议。 BaseProtocal wrapper = new ModbusTcpProtocal(); + //调用方法一:手动构造 + //第一步:先生成一个输入信息的object数组 object[] inputObjects = new object[]{(byte)0x11,(byte)0x01,(short)0x13,(short)0x25}; + //第二步:向仪器发送这个信息,并接收信息 byte[] outputBytes = wrapper.SendReceive(inputObjects); + //第三步:输出信息 for (int i = 0; i < outputBytes.Length; i++) { Console.WriteLine(outputBytes[i]); @@ -24,8 +29,12 @@ namespace NA200H.UI.ConsoleApp Console.Read(); Console.Read(); + //调用方法二:自动构造 + //第一步:先生成一个输入结构体,然后向这个结构体中填写数据 ReadCoilStatusModbusProtocal.ReadCoilStatusInputStruct readCoilStatusInputStruct = new ReadCoilStatusModbusProtocal.ReadCoilStatusInputStruct(0x11, "Q20", 0x25); + //第二步:再生成一个输出结构体,执行相应协议的发送指令,并将输出信息自动转换到输出结构体中 ReadCoilStatusModbusProtocal.ReadCoilStatusOutputStruct readCoilStatusOutputStruct = (ReadCoilStatusModbusProtocal.ReadCoilStatusOutputStruct)wrapper.SendReceive(wrapper["ReadCoilStatusModbusProtocal"], readCoilStatusInputStruct); + //第三步:读取这个输出结构体的信息。 for (int i = 0; i < readCoilStatusOutputStruct.CoilStatus.Length; i++) { Console.WriteLine(readCoilStatusOutputStruct.CoilStatus[i]);