From 3f4fe27a5e9f295c9adb5fa28acdde7145179391 Mon Sep 17 00:00:00 2001 From: "parallelbgls@outlook.com" Date: Thu, 16 Oct 2014 16:38:21 +0800 Subject: [PATCH] 2014-10-16 update 1 --- .../Controllers/CrossLampController.cs | 14 +- .../CrossLampControl.WebApi/信号灯.mwp | Bin 31585 -> 31609 bytes Modbus.Net/ModBus.Net/AddressTranslator.cs | 56 ++ Modbus.Net/ModBus.Net/BaseConnector.cs | 1 + Modbus.Net/ModBus.Net/BaseProtocal.cs | 43 +- Modbus.Net/ModBus.Net/BaseUtility.cs | 38 +- Modbus.Net/ModBus.Net/ComConnector.cs | 5 + Modbus.Net/ModBus.Net/ComProtocalLinker.cs | 6 +- .../ConfigurationManager.Designer.cs | 9 + .../ModBus.Net/ConfigurationManager.resx | 3 + Modbus.Net/ModBus.Net/ModBus.Net.csproj | 5 + Modbus.Net/ModBus.Net/ModbusProtocal.cs | 54 +- Modbus.Net/ModBus.Net/ModbusRtuProtocal.cs | 5 +- .../ModBus.Net/ModbusRtuProtocalLinker.cs | 5 - Modbus.Net/ModBus.Net/ModbusTCPProtocal.cs | 5 +- .../ModBus.Net/ModbusTcpProtocalLinker.cs | 7 +- Modbus.Net/ModBus.Net/ModbusUtility.cs | 38 +- .../ModBus.Net/Properties/AssemblyInfo.cs | 4 +- Modbus.Net/ModBus.Net/ProtocalLinker.cs | 26 +- Modbus.Net/ModBus.Net/ProtocalUnit.cs | 13 +- Modbus.Net/ModBus.Net/SimenseProtocal.cs | 519 ++++++++++++++++++ .../SimenseProtocalLinkerBytesExtend.cs | 25 + Modbus.Net/ModBus.Net/SimenseTcpProtocal.cs | 71 +++ .../ModBus.Net/SimenseTcpProtocalLinker.cs | 39 ++ Modbus.Net/ModBus.Net/SimenseUtility.cs | 120 ++++ Modbus.Net/ModBus.Net/TcpConnector.cs | 8 +- Modbus.Net/ModBus.Net/TcpProtocalLinker.cs | 14 +- Modbus.Net/ModBus.Net/ValueHelper.cs | 13 + Modbus.Net/NA200H.UI.Console/Program.cs | 74 ++- Modbus.Net/NA200H.UI.WPF/3ADD.mwp | Bin 24155 -> 24135 bytes Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs | 29 +- 31 files changed, 1072 insertions(+), 177 deletions(-) create mode 100644 Modbus.Net/ModBus.Net/SimenseProtocal.cs create mode 100644 Modbus.Net/ModBus.Net/SimenseProtocalLinkerBytesExtend.cs create mode 100644 Modbus.Net/ModBus.Net/SimenseTcpProtocal.cs create mode 100644 Modbus.Net/ModBus.Net/SimenseTcpProtocalLinker.cs create mode 100644 Modbus.Net/ModBus.Net/SimenseUtility.cs diff --git a/Modbus.Net/CrossLampControl.WebApi/Controllers/CrossLampController.cs b/Modbus.Net/CrossLampControl.WebApi/Controllers/CrossLampController.cs index 13ace08..bb78bba 100644 --- a/Modbus.Net/CrossLampControl.WebApi/Controllers/CrossLampController.cs +++ b/Modbus.Net/CrossLampControl.WebApi/Controllers/CrossLampController.cs @@ -12,16 +12,22 @@ namespace CrossLampControl.WebApi.Controllers { public class CrossLampController : ApiController { - ModbusUtility _utility = new ModbusUtility((int)ModbusType.Rtu, "COM3"); + BaseUtility _utility; + + public CrossLampController() + { + _utility = new SimenseUtility(SimenseType.Tcp, "192.168.3.241,200"); + _utility.AddressTranslator = new AddressTranslatorSimense(); + } + [HttpGet] public Lamp GetLamp() { Lamp light = new Lamp(); - byte[] lampsbyte = _utility.GetDatas(2, ((byte)ModbusProtocalReadDataFunctionCode.ReadCoilStatus).ToString()+":0", 6); + object[] lampsbyte = _utility.GetDatas(2, 0, "Q0", new KeyValuePair(typeof(bool), 7)); bool[] lamps = ValueHelper.Instance.ObjectArrayToDestinationArray( - ValueHelper.Instance.ByteArrayToObjectArray(lampsbyte, - new KeyValuePair(typeof (bool), 7))); + lampsbyte); if (lamps[0]) { light.MainLamp = LightLamp.Green.ToString(); diff --git a/Modbus.Net/CrossLampControl.WebApi/信号灯.mwp b/Modbus.Net/CrossLampControl.WebApi/信号灯.mwp index bf343d6846c2024d55735e4f04403d2b403c619b..e22746e239b54768afaace49655e6fbad43cd8d4 100644 GIT binary patch delta 31127 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%0DdrS5e1rVKmMxrAFmqfL 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 diff --git a/Modbus.Net/ModBus.Net/AddressTranslator.cs b/Modbus.Net/ModBus.Net/AddressTranslator.cs index 143ba83..6e530f3 100644 --- a/Modbus.Net/ModBus.Net/AddressTranslator.cs +++ b/Modbus.Net/ModBus.Net/AddressTranslator.cs @@ -9,6 +9,12 @@ namespace ModBus.Net /// public abstract class AddressTranslator { + /// + /// 地址转换 + /// + /// 地址前地址 + /// 是否为读取,是为读取,否为写入 + /// Key为转换后的地址,Value为辅助码 public abstract KeyValuePair AddressTranslate(string address, bool isRead); } @@ -97,4 +103,54 @@ namespace ModBus.Net throw new FormatException(); } } + + public class AddressTranslatorSimense : AddressTranslator + { + protected Dictionary AreaCodeDictionary; + + public AddressTranslatorSimense() + { + AreaCodeDictionary = new Dictionary + { + {"S", 0x04}, + {"SM", 0x05}, + {"AI", 0x06}, + {"AQ", 0x07}, + {"C", 0x1E}, + {"T", 0x1F}, + {"HC", 0x20}, + {"I", 0x81}, + {"Q", 0x82}, + {"M", 0x83}, + {"DB", 0x84}, + {"V", 0x184}, + }; + } + + public override KeyValuePair AddressTranslate(string address, bool isRead) + { + address = address.ToUpper(); + if (address.Substring(0,2) == "DB") + { + var addressSplit = address.Split('.'); + if (addressSplit.Length != 2) throw new FormatException(); + addressSplit[0] = addressSplit[0].Substring(2); + if (addressSplit[1].Substring(0, 2) == "DB") + addressSplit[1] = addressSplit[1].Substring(2); + return new KeyValuePair(int.Parse(addressSplit[1]), int.Parse(addressSplit[0]) * 256 + AreaCodeDictionary["DB"]); + } + int i = 0; + int t; + while (!int.TryParse(address[i].ToString(), out t) && i < address.Length) + { + i++; + } + if (i == 0 || i >= address.Length) throw new FormatException(); + string head = address.Substring(0, i); + string tail = address.Substring(i); + return + new KeyValuePair(int.Parse(tail), + AreaCodeDictionary[head]); + } + } } \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/BaseConnector.cs b/Modbus.Net/ModBus.Net/BaseConnector.cs index 4aacf2b..a6f97f6 100644 --- a/Modbus.Net/ModBus.Net/BaseConnector.cs +++ b/Modbus.Net/ModBus.Net/BaseConnector.cs @@ -8,6 +8,7 @@ namespace ModBus.Net { public abstract class BaseConnector { + public abstract bool IsConnected { get; } /// /// 连接PLC /// diff --git a/Modbus.Net/ModBus.Net/BaseProtocal.cs b/Modbus.Net/ModBus.Net/BaseProtocal.cs index d1f2232..407a9ab 100644 --- a/Modbus.Net/ModBus.Net/BaseProtocal.cs +++ b/Modbus.Net/ModBus.Net/BaseProtocal.cs @@ -14,7 +14,7 @@ namespace ModBus.Net /// /// 需要发送的数据 /// 数据是否正确接收 - protected ProtocalLinker _protocalLinker; + public ProtocalLinker ProtocalLinker { get; protected set; } protected BaseProtocal() { @@ -26,17 +26,18 @@ namespace ModBus.Net /// /// 协议的类的名称 /// - public ProtocalUnit this[string protocalName] + public ProtocalUnit this[Type type] { get { + string protocalName = type.FullName; if (Protocals.ContainsKey(protocalName)) { return Protocals[protocalName]; } //自动寻找存在的协议并将其加载 var protocalUnit = - Assembly.Load("ModBus.Net").CreateInstance("ModBus.Net." + protocalName) as ProtocalUnit; + Assembly.Load("ModBus.Net").CreateInstance(protocalName) as ProtocalUnit; if (protocalUnit == null) throw new InvalidCastException("没有相应的协议内容"); Register(protocalUnit); return Protocals[protocalName]; @@ -48,7 +49,7 @@ namespace ModBus.Net protected void Register(ProtocalUnit linkProtocal) { if (linkProtocal == null) return; - Protocals.Add(linkProtocal.GetType().Name, linkProtocal); + Protocals.Add(linkProtocal.GetType().FullName, linkProtocal); } /// @@ -58,8 +59,7 @@ namespace ModBus.Net /// public virtual byte[] SendReceive(params object[] content) { - int t; - return _protocalLinker.SendReceive(ProtocalUnit.TranslateContent(content)); + return ProtocalLinker.SendReceive(ProtocalUnit.TranslateContent(content)); } /// @@ -71,29 +71,16 @@ namespace ModBus.Net public virtual OutputStruct SendReceive(ProtocalUnit unit, InputStruct content) { int t = 0; - return unit.Unformat(_protocalLinker.SendReceive(unit.Format(content)), ref t); + //如果为特别处理协议的话,跳过协议扩展收缩 + if (unit is SpecialProtocalUnit) + { + return unit.Unformat(ProtocalLinker.SendReceiveWithoutExtAndDec(unit.Format(content)), ref t); + } + else + { + return unit.Unformat(ProtocalLinker.SendReceive(unit.Format(content)), ref t); + } } - /// - /// 仅发送数据 - /// - /// - /// - /// - 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)); - } } } \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/BaseUtility.cs b/Modbus.Net/ModBus.Net/BaseUtility.cs index fac303b..36e743f 100644 --- a/Modbus.Net/ModBus.Net/BaseUtility.cs +++ b/Modbus.Net/ModBus.Net/BaseUtility.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -12,6 +13,7 @@ namespace ModBus.Net /// 协议收发主体 /// protected BaseProtocal Wrapper; + public virtual string ConnectionString { get; set; } public AddressTranslator AddressTranslator { get; set; } @@ -20,11 +22,6 @@ namespace ModBus.Net AddressTranslator = new AddressTranslatorBase(); } /// - /// 设置连接字符串 - /// - /// 连接字符串 - public abstract void SetConnectionString(string connectionString); - /// /// 设置连接类型 /// /// 连接类型 @@ -33,18 +30,43 @@ namespace ModBus.Net /// 获取数据 /// /// 从站地址 + /// 主站地址 /// 开始地址 - /// 接收个数 + /// 获取类型和个数 /// 接收到的byte数据 - public abstract byte[] GetDatas(byte belongAddress, string startAddress, int getCount); + protected abstract byte[] GetDatas(byte belongAddress, byte masterAddress, string startAddress, int getByteCount); + + public virtual object[] GetDatas(byte belongAddress, byte masterAddress, string startAddress, + KeyValuePair getTypeAndCount) + { + string typeName = getTypeAndCount.Key.FullName; + double bCount = ValueHelper.Instance.ByteLength[typeName]; + byte[] getBytes = GetDatas(belongAddress, masterAddress, startAddress, (int)Math.Ceiling(bCount * getTypeAndCount.Value)); + return ValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCount); + } + + public virtual object[] GetDatas(byte belongAddress, byte masterAddress, string startAddress, + IEnumerable> getTypeAndCountList) + { + int bAllCount = 0; + foreach (var getTypeAndCount in getTypeAndCountList) + { + string typeName = getTypeAndCount.Key.FullName; + double bCount = ValueHelper.Instance.ByteLength[typeName]; + bAllCount += (int)Math.Ceiling(bCount*getTypeAndCount.Value); + } + byte[] getBytes = GetDatas(belongAddress, masterAddress, startAddress, bAllCount); + return ValueHelper.Instance.ByteArrayToObjectArray(getBytes, getTypeAndCountList); + } /// /// 设置数据 /// /// 从站地址 + /// 主站地址 /// 开始地址 /// 设置数据 /// 是否设置成功 - public abstract bool SetDatas(byte belongAddress, string startAddress, object[] setContents); + public abstract bool SetDatas(byte belongAddress, byte masterAddress, string startAddress, object[] setContents); /// /// 获取PLC时间 diff --git a/Modbus.Net/ModBus.Net/ComConnector.cs b/Modbus.Net/ModBus.Net/ComConnector.cs index 1c1abe7..e7dfe30 100644 --- a/Modbus.Net/ModBus.Net/ComConnector.cs +++ b/Modbus.Net/ModBus.Net/ComConnector.cs @@ -30,6 +30,11 @@ namespace ModBus.Net #region 发送接收数据 + public override bool IsConnected + { + get { return serialPort1 != null && serialPort1.IsOpen; } + } + public override bool Connect() { if (serialPort1 != null) diff --git a/Modbus.Net/ModBus.Net/ComProtocalLinker.cs b/Modbus.Net/ModBus.Net/ComProtocalLinker.cs index f397213..012d74b 100644 --- a/Modbus.Net/ModBus.Net/ComProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/ComProtocalLinker.cs @@ -8,14 +8,14 @@ namespace ModBus.Net { public abstract class ComProtocalLinker : ProtocalLinker { - protected ComProtocalLinker() + protected ComProtocalLinker() : this(ConfigurationManager.COM) { - //初始化连对象 - _baseConnector = new ComConnector(ConfigurationManager.COM); + } protected ComProtocalLinker(string com) { + //初始化连对象 _baseConnector = new ComConnector(com); } } diff --git a/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs b/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs index 213e4ff..b505169 100644 --- a/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs +++ b/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs @@ -77,5 +77,14 @@ namespace ModBus.Net { return ResourceManager.GetString("IP", resourceCulture); } } + + /// + /// 查找类似 502 的本地化字符串。 + /// + internal static string Port { + get { + return ResourceManager.GetString("Port", resourceCulture); + } + } } } diff --git a/Modbus.Net/ModBus.Net/ConfigurationManager.resx b/Modbus.Net/ModBus.Net/ConfigurationManager.resx index 1303957..2564898 100644 --- a/Modbus.Net/ModBus.Net/ConfigurationManager.resx +++ b/Modbus.Net/ModBus.Net/ConfigurationManager.resx @@ -123,4 +123,7 @@ 192.168.3.247 + + 502 + \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/ModBus.Net.csproj b/Modbus.Net/ModBus.Net/ModBus.Net.csproj index 94c37aa..290f210 100644 --- a/Modbus.Net/ModBus.Net/ModBus.Net.csproj +++ b/Modbus.Net/ModBus.Net/ModBus.Net.csproj @@ -65,6 +65,11 @@ + + + + + Code diff --git a/Modbus.Net/ModBus.Net/ModbusProtocal.cs b/Modbus.Net/ModBus.Net/ModbusProtocal.cs index 9cbc00b..794122d 100644 --- a/Modbus.Net/ModBus.Net/ModbusProtocal.cs +++ b/Modbus.Net/ModBus.Net/ModbusProtocal.cs @@ -11,7 +11,7 @@ internal enum ModbusProtocalVariableFunctionCode : byte /// /// 跟时间有关的功能码 /// -internal enum ModbusProtocalTimeFunctionCode : byte +public enum ModbusProtocalTimeFunctionCode : byte { GetSystemTime = 3, SetSystemTime = 16, @@ -31,7 +31,7 @@ public enum ModbusProtocalReadDataFunctionCode : byte /// /// 跟写数据有关的功能码 /// -public enum ModbusProtocalWriteDataFunctionCode : byte +internal enum ModbusProtocalWriteDataFunctionCode : byte { WriteMultiCoil = 15, WriteMultiRegister = 16, @@ -45,9 +45,9 @@ namespace ModBus.Net } #region 读PLC数据 - public class ReadDataInputStruct : InputStruct + public class ReadDataModbusInputStruct : InputStruct { - public ReadDataInputStruct(byte belongAddress, string startAddress, ushort getCount, AddressTranslator addressTranslator) + public ReadDataModbusInputStruct(byte belongAddress, string startAddress, ushort getCount, AddressTranslator addressTranslator) { BelongAddress = belongAddress; KeyValuePair translateAddress = addressTranslator.AddressTranslate(startAddress, true); @@ -65,9 +65,9 @@ namespace ModBus.Net public ushort GetCount { get; private set; } } - public class ReadDataOutputStruct : OutputStruct + public class ReadDataModbusOutputStruct : OutputStruct { - public ReadDataOutputStruct(byte belongAddress, byte functionCode, + public ReadDataModbusOutputStruct(byte belongAddress, byte functionCode, int dataCount, byte[] dataValue) { BelongAddress = belongAddress; @@ -89,7 +89,7 @@ namespace ModBus.Net { public override byte[] Format(InputStruct message) { - var r_message = (ReadDataInputStruct)message; + var r_message = (ReadDataModbusInputStruct)message; return Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.GetCount); } @@ -101,16 +101,16 @@ namespace ModBus.Net byte dataCount = ValueHelper.Instance.GetByte(messageBytes, ref pos); byte[] dataValue = new byte[dataCount]; Array.Copy(messageBytes, 3, dataValue, 0, dataCount); - return new ReadDataOutputStruct(belongAddress, functionCode, dataCount, dataValue); + return new ReadDataModbusOutputStruct(belongAddress, functionCode, dataCount, dataValue); } } #endregion #region 写PLC数据 - public class WriteDataInputStruct : InputStruct + public class WriteDataModbusInputStruct : InputStruct { - public WriteDataInputStruct(byte belongAddress, string startAddress, object[] writeValue, AddressTranslator addressTranslator) + public WriteDataModbusInputStruct(byte belongAddress, string startAddress, object[] writeValue, AddressTranslator addressTranslator) { BelongAddress = belongAddress; KeyValuePair translateAddress = addressTranslator.AddressTranslate(startAddress, false); @@ -118,7 +118,7 @@ namespace ModBus.Net StartAddress = (ushort)translateAddress.Key; WriteCount = (ushort)writeValue.Length; WriteByteCount = 0; - WriteValue = writeValue.Clone() as object[]; + WriteValue = writeValue; } public byte BelongAddress { get; private set; } @@ -134,9 +134,9 @@ namespace ModBus.Net public object[] WriteValue { get; private set; } } - public class WriteDataOutputStruct : OutputStruct + public class WriteDataModbusOutputStruct : OutputStruct { - public WriteDataOutputStruct(byte belongAddress, byte functionCode, + public WriteDataModbusOutputStruct(byte belongAddress, byte functionCode, ushort startAddress, ushort writeCount) { BelongAddress = belongAddress; @@ -161,7 +161,7 @@ namespace ModBus.Net { public override byte[] Format(InputStruct message) { - var r_message = (WriteDataInputStruct)message; + var r_message = (WriteDataModbusInputStruct)message; byte[] formattingBytes = Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, r_message.WriteValue); formattingBytes[6] = (byte)(formattingBytes.Length - 7); @@ -174,7 +174,7 @@ namespace ModBus.Net byte functionCode = ValueHelper.Instance.GetByte(messageBytes, ref flag); ushort startAddress = ValueHelper.Instance.GetUShort(messageBytes, ref flag); ushort writeCount = ValueHelper.Instance.GetUShort(messageBytes, ref flag); - return new WriteDataOutputStruct(belongAddress, functionCode, startAddress, + return new WriteDataModbusOutputStruct(belongAddress, functionCode, startAddress, writeCount); } } @@ -182,9 +182,9 @@ namespace ModBus.Net #endregion #region 读PLC时间 - public class GetSystemTimeInputStruct : InputStruct + public class GetSystemTimeModbusInputStruct : InputStruct { - public GetSystemTimeInputStruct(byte belongAddress) + public GetSystemTimeModbusInputStruct(byte belongAddress) { BelongAddress = belongAddress; FunctionCode = (byte)ModbusProtocalTimeFunctionCode.GetSystemTime; @@ -201,9 +201,9 @@ namespace ModBus.Net public ushort GetCount { get; private set; } } - public class GetSystemTimeOutputStruct : OutputStruct + public class GetSystemTimeModbusOutputStruct : OutputStruct { - public GetSystemTimeOutputStruct(byte belongAddress, byte functionCode, + public GetSystemTimeModbusOutputStruct(byte belongAddress, byte functionCode, byte writeByteCount, ushort year, byte day, byte month, ushort hour, byte second, byte minute, ushort millisecond) { @@ -229,7 +229,7 @@ namespace ModBus.Net { public override byte[] Format(InputStruct message) { - var r_message = (GetSystemTimeInputStruct)message; + var r_message = (GetSystemTimeModbusInputStruct)message; return Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.GetCount); } @@ -246,7 +246,7 @@ namespace ModBus.Net byte second = ValueHelper.Instance.GetByte(messageBytes, ref flag); byte minute = ValueHelper.Instance.GetByte(messageBytes, ref flag); ushort millisecond = ValueHelper.Instance.GetUShort(messageBytes, ref flag); - return new GetSystemTimeOutputStruct(belongAddress, functionCode, writeByteCount, year, day, + return new GetSystemTimeModbusOutputStruct(belongAddress, functionCode, writeByteCount, year, day, month, hour, second, minute, millisecond); } } @@ -254,9 +254,9 @@ namespace ModBus.Net #endregion #region 写PLC时间 - public class SetSystemTimeInputStruct : InputStruct + public class SetSystemTimeModbusInputStruct : InputStruct { - public SetSystemTimeInputStruct(byte belongAddress, DateTime time) + public SetSystemTimeModbusInputStruct(byte belongAddress, DateTime time) { BelongAddress = belongAddress; FunctionCode = (byte)ModbusProtocalTimeFunctionCode.SetSystemTime; @@ -297,9 +297,9 @@ namespace ModBus.Net public ushort Millisecond { get; private set; } } - public class SetSystemTimeOutputStruct : OutputStruct + public class SetSystemTimeModbusOutputStruct : OutputStruct { - public SetSystemTimeOutputStruct(byte belongAddress, byte functionCode, + public SetSystemTimeModbusOutputStruct(byte belongAddress, byte functionCode, ushort startAddress, ushort writeCount) { BelongAddress = belongAddress; @@ -324,7 +324,7 @@ namespace ModBus.Net { public override byte[] Format(InputStruct message) { - var r_message = (SetSystemTimeInputStruct)message; + var r_message = (SetSystemTimeModbusInputStruct)message; return Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, r_message.Year, r_message.Day, @@ -337,7 +337,7 @@ namespace ModBus.Net byte functionCode = ValueHelper.Instance.GetByte(messageBytes, ref flag); ushort startAddress = ValueHelper.Instance.GetUShort(messageBytes, ref flag); ushort writeCount = ValueHelper.Instance.GetUShort(messageBytes, ref flag); - return new SetSystemTimeOutputStruct(belongAddress, functionCode, startAddress, writeCount); + return new SetSystemTimeModbusOutputStruct(belongAddress, functionCode, startAddress, writeCount); } } #endregion diff --git a/Modbus.Net/ModBus.Net/ModbusRtuProtocal.cs b/Modbus.Net/ModBus.Net/ModbusRtuProtocal.cs index 2e1b420..415f5e8 100644 --- a/Modbus.Net/ModBus.Net/ModbusRtuProtocal.cs +++ b/Modbus.Net/ModBus.Net/ModbusRtuProtocal.cs @@ -11,14 +11,13 @@ namespace ModBus.Net /// public class ModbusRtuProtocal : ModbusProtocal { - public ModbusRtuProtocal() + public ModbusRtuProtocal() : this(ConfigurationManager.COM) { - _protocalLinker = new ModbusRtuProtocalLinker(); } public ModbusRtuProtocal(string com) { - _protocalLinker = new ModbusRtuProtocalLinker(com); + ProtocalLinker = new ModbusRtuProtocalLinker(com); } } } diff --git a/Modbus.Net/ModBus.Net/ModbusRtuProtocalLinker.cs b/Modbus.Net/ModBus.Net/ModbusRtuProtocalLinker.cs index 68fb74b..44a998f 100644 --- a/Modbus.Net/ModBus.Net/ModbusRtuProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/ModbusRtuProtocalLinker.cs @@ -23,11 +23,6 @@ namespace ModBus.Net return true; } - public ModbusRtuProtocalLinker() : this(ConfigurationManager.COM) - { - - } - public ModbusRtuProtocalLinker(string com) : base(com) { diff --git a/Modbus.Net/ModBus.Net/ModbusTCPProtocal.cs b/Modbus.Net/ModBus.Net/ModbusTCPProtocal.cs index 372ed5c..1d3350c 100644 --- a/Modbus.Net/ModBus.Net/ModbusTCPProtocal.cs +++ b/Modbus.Net/ModBus.Net/ModbusTCPProtocal.cs @@ -7,14 +7,13 @@ namespace ModBus.Net /// public class ModbusTcpProtocal : ModbusProtocal { - public ModbusTcpProtocal() + public ModbusTcpProtocal() : this(ConfigurationManager.IP) { - _protocalLinker = new ModbusTcpProtocalLinker(); } public ModbusTcpProtocal(string ip) { - _protocalLinker = new ModbusTcpProtocalLinker(ip); + ProtocalLinker = new ModbusTcpProtocalLinker(ip); } } } \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/ModbusTcpProtocalLinker.cs b/Modbus.Net/ModBus.Net/ModbusTcpProtocalLinker.cs index 3b65b17..f8f3d99 100644 --- a/Modbus.Net/ModBus.Net/ModbusTcpProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/ModbusTcpProtocalLinker.cs @@ -23,12 +23,7 @@ namespace ModBus.Net return true; } - public ModbusTcpProtocalLinker() : this(ConfigurationManager.IP) - { - - } - - public ModbusTcpProtocalLinker(string ip) : base(ip) + public ModbusTcpProtocalLinker(string ip) : base(ip, 102) { } diff --git a/Modbus.Net/ModBus.Net/ModbusUtility.cs b/Modbus.Net/ModBus.Net/ModbusUtility.cs index 036183e..56fd508 100644 --- a/Modbus.Net/ModBus.Net/ModbusUtility.cs +++ b/Modbus.Net/ModBus.Net/ModbusUtility.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Windows.Forms; /// @@ -21,8 +22,6 @@ namespace ModBus.Net { public class ModbusUtility : BaseUtility { - protected string ConnectionString { get; set; } - private ModbusType _modbusType; public ModbusType ModbusType @@ -56,15 +55,10 @@ namespace ModBus.Net ModbusType = (ModbusType)connectionType; } - public ModbusUtility(int connectionType, string connectionString) - { - ConnectionString = connectionString; - ModbusType = (ModbusType)connectionType; - } - - public override void SetConnectionString(string connectionString) + public ModbusUtility(ModbusType connectionType, string connectionString) { ConnectionString = connectionString; + ModbusType = connectionType; } public override void SetConnectionType(int connectionType) @@ -72,13 +66,13 @@ namespace ModBus.Net ModbusType = (ModbusType) connectionType; } - public override byte[] GetDatas(byte belongAddress, string startAddress, int getCount) + protected override byte[] GetDatas(byte belongAddress, byte materAddress, string startAddress, int getByteCount) { try { - var inputStruct = new ReadDataInputStruct(belongAddress, startAddress, getCount % 2 == 0 ? (ushort)(getCount / 2) : (ushort)(getCount / 2 + 1), AddressTranslator); + var inputStruct = new ReadDataModbusInputStruct(belongAddress, startAddress, getByteCount % 2 == 0 ? (ushort)(getByteCount / 2) : (ushort)(getByteCount / 2 + 1), AddressTranslator); var outputStruct = - Wrapper.SendReceive(Wrapper["ReadDataModbusProtocal"], inputStruct) as ReadDataOutputStruct; + Wrapper.SendReceive(Wrapper[typeof(ReadDataModbusProtocal)], inputStruct) as ReadDataModbusOutputStruct; return outputStruct.DataValue; } catch @@ -87,14 +81,14 @@ namespace ModBus.Net } } - public override bool SetDatas(byte belongAddress, string startAddress, object[] setContents) + public override bool SetDatas(byte belongAddress, byte materAddress, string startAddress, object[] setContents) { try { - var inputStruct = new WriteDataInputStruct(belongAddress, startAddress, setContents, AddressTranslator); + var inputStruct = new WriteDataModbusInputStruct(belongAddress, startAddress, setContents, AddressTranslator); var outputStruct = - Wrapper.SendReceive(Wrapper["WriteDataModbusProtocal"], inputStruct) as - WriteDataOutputStruct; + Wrapper.SendReceive(Wrapper[typeof(WriteDataModbusProtocal)], inputStruct) as + WriteDataModbusOutputStruct; if (outputStruct.WriteCount != setContents.Length) return false; return true; } @@ -108,10 +102,10 @@ namespace ModBus.Net { try { - var inputStruct = new GetSystemTimeInputStruct(belongAddress); + var inputStruct = new GetSystemTimeModbusInputStruct(belongAddress); var outputStruct = - Wrapper.SendReceive(Wrapper["GetSystemTimeModbusProtocal"], inputStruct) as - GetSystemTimeOutputStruct; + Wrapper.SendReceive(Wrapper[typeof(GetSystemTimeModbusProtocal)], inputStruct) as + GetSystemTimeModbusOutputStruct; return outputStruct.Time; } catch (Exception) @@ -124,10 +118,10 @@ namespace ModBus.Net { try { - var inputStruct = new SetSystemTimeInputStruct(belongAddress, setTime); + var inputStruct = new SetSystemTimeModbusInputStruct(belongAddress, setTime); var outputStruct = - Wrapper.SendReceive(Wrapper["SetSystemTimeModbusProtocal"], inputStruct) as - SetSystemTimeOutputStruct; + Wrapper.SendReceive(Wrapper[typeof(SetSystemTimeModbusProtocal)], inputStruct) as + SetSystemTimeModbusOutputStruct; return outputStruct.WriteCount > 0; } catch (Exception) diff --git a/Modbus.Net/ModBus.Net/Properties/AssemblyInfo.cs b/Modbus.Net/ModBus.Net/Properties/AssemblyInfo.cs index 24c8a2a..b25dbe9 100644 --- a/Modbus.Net/ModBus.Net/Properties/AssemblyInfo.cs +++ b/Modbus.Net/ModBus.Net/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // 方法是按如下所示使用“*”: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.0.1008")] -[assembly: AssemblyFileVersion("0.1.0.1008")] \ No newline at end of file +[assembly: AssemblyVersion("0.2.0.1016")] +[assembly: AssemblyFileVersion("0.2.0.1016")] \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/ProtocalLinker.cs b/Modbus.Net/ModBus.Net/ProtocalLinker.cs index 9f2f959..ae33d7d 100644 --- a/Modbus.Net/ModBus.Net/ProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/ProtocalLinker.cs @@ -9,6 +9,10 @@ namespace ModBus.Net { protected BaseConnector _baseConnector; + public bool IsConnected + { + get { return _baseConnector.IsConnected; } + } /// /// 发送并接收数据 /// @@ -16,22 +20,24 @@ namespace ModBus.Net /// 接收协议的内容 public virtual byte[] SendReceive(byte[] content) { - //接收数据 - byte[] receiveBytes = _baseConnector.SendMsg(BytesExtend(content)); - //容错处理 - if (!CheckRight(receiveBytes)) return null; - //返回数据 - return BytesDecact(receiveBytes); + byte[] extBytes = BytesExtend(content); + byte[] receiveBytes = SendReceiveWithoutExtAndDec(extBytes); + return receiveBytes == null ? null : BytesDecact(receiveBytes); } /// - /// 仅发送数据 + /// 发送并接收数据,不进行协议扩展和收缩,用于特殊协议 /// /// 发送协议的内容 - /// 协议是否正确发送 - public virtual bool SendOnly(byte[] content) + /// 接收协议的内容 + public virtual byte[] SendReceiveWithoutExtAndDec(byte[] content) { - return _baseConnector.SendMsgWithoutReturn(BytesExtend(content)); + //发送数据 + byte[] receiveBytes = _baseConnector.SendMsg(content); + //容错处理 + if (!CheckRight(receiveBytes)) return null; + //返回字符 + return receiveBytes; } /// diff --git a/Modbus.Net/ModBus.Net/ProtocalUnit.cs b/Modbus.Net/ModBus.Net/ProtocalUnit.cs index c109b8b..d40557a 100644 --- a/Modbus.Net/ModBus.Net/ProtocalUnit.cs +++ b/Modbus.Net/ModBus.Net/ProtocalUnit.cs @@ -7,14 +7,6 @@ namespace ModBus.Net { public abstract class ProtocalUnit : IProtocalFormatting { - //protected static AddressTranslator _addressTranslator = new AddressTranslatorBase(); - - public ProtocalUnit SetAddressTranslator(/*AddressTranslator addressTranslator*/) - { - //_addressTranslator = addressTranslator; - return this; - } - /// /// 格式化,将输入结构转换为字节数组 /// @@ -51,6 +43,11 @@ namespace ModBus.Net } } + public abstract class SpecialProtocalUnit : ProtocalUnit + { + + } + /// /// 输入结构 /// diff --git a/Modbus.Net/ModBus.Net/SimenseProtocal.cs b/Modbus.Net/ModBus.Net/SimenseProtocal.cs new file mode 100644 index 0000000..fae46cc --- /dev/null +++ b/Modbus.Net/ModBus.Net/SimenseProtocal.cs @@ -0,0 +1,519 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Windows.Forms; + +public enum SimenseTypeCode : byte +{ + Bool = 0x01, + Byte = 0x02, + Word = 0x03, + DWord = 0x04, + C = 0x1E, + T = 0x1F, + HC = 0x20, +}; + +public enum SimenseAccessResult : byte +{ + NoError = 0xFF, + HardwareFault = 0x01, + IllegalObjectAccess = 0x03, + InvalidAddress = 0x05, + DataTypeNotSupport = 0x06, + ObjNotExistOrLengthError = 0x0A, +}; + +public enum SimenseDataType : byte +{ + Error = 0x00, + BitAccess = 0x03, + OtherAccess = 0x04 +}; + +namespace ModBus.Net +{ + public abstract class SimenseProtocal : BaseProtocal + { + + } + + internal class CreateReferenceSimenseInputStruct : InputStruct + { + public CreateReferenceSimenseInputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap) + { + TdpuSize = tdpuSize; + TsapSrc = srcTsap; + TsapDst = dstTsap; + } + + public byte TdpuSize; + + public ushort TsapSrc; + + public ushort TsapDst; + } + + internal class CreateReferenceSimenseOutputStruct : OutputStruct + { + public CreateReferenceSimenseOutputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap) + { + TdpuSize = tdpuSize; + TsapSrc = srcTsap; + TsapDst = dstTsap; + } + + public byte TdpuSize { get; private set; } + public ushort TsapSrc { get; private set; } + public ushort TsapDst { get; private set; } + } + + internal class CreateReferenceSimenseProtocal : SpecialProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (CreateReferenceSimenseInputStruct)message; + const ushort head = 0x0300; + const ushort len = 0x0016; + const byte contentLen = 0x11; + const byte typeCode = 0xe0; + const ushort dstRef = 0x0000; + const ushort srcRef = 0x000c; + const byte reserved = 0x00; + const ushort tdpuSizeCode = 0xc001; + byte tdpuSizeContent = r_message.TdpuSize; + const ushort srcTsapCode = 0xc102; + ushort srcTsapContent = r_message.TsapSrc; + const ushort dstTsapCode = 0xc202; + ushort dstTsapContent = r_message.TsapDst; + return Format(head, len, contentLen, typeCode, dstRef, srcRef, reserved, tdpuSizeCode, tdpuSizeContent, + srcTsapCode, srcTsapContent, dstTsapCode, dstTsapContent); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 11; + byte tdpuSize = 0; + ushort srcTsap = 0, dstTsap = 0; + switch (messageBytes[pos]) + { + case 0xc0: + { + pos += 2; + tdpuSize = ValueHelper.Instance.GetByte(messageBytes, ref pos); + break; + } + case 0xc1: + { + pos += 2; + srcTsap = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + break; + } + case 0xc2: + { + pos += 2; + dstTsap = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + break; + } + } + return new CreateReferenceSimenseOutputStruct(tdpuSize, srcTsap, dstTsap); + } + } + + internal class EstablishAssociationSimenseInputStruct : InputStruct + { + public EstablishAssociationSimenseInputStruct(ushort pduRef, ushort maxCalling, ushort maxCalled, ushort maxPdu) + { + PduRef = pduRef; + MaxCalling = maxCalling; + MaxCalled = maxCalled; + MaxPdu = maxPdu; + } + + public ushort PduRef { get; private set; } + public ushort MaxCalling { get; private set; } + public ushort MaxCalled { get; private set; } + public ushort MaxPdu { get; private set; } + } + + internal class EstablishAssociationSimenseOutputStruct : OutputStruct + { + public EstablishAssociationSimenseOutputStruct(ushort pduRef, ushort maxCalling, ushort maxCalled, ushort maxPdu) + { + PduRef = pduRef; + MaxCalling = maxCalling; + MaxCalled = maxCalled; + MaxPdu = maxPdu; + } + + public ushort PduRef { get; private set; } + public ushort MaxCalling { get; private set; } + public ushort MaxCalled { get; private set; } + public ushort MaxPdu { get; private set; } + } + + internal class EstablishAssociationSimenseProtocal : ProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (EstablishAssociationSimenseInputStruct) message; + const byte protoId = 0x32; + const byte rosctr = 0x01; + const ushort redId = 0x0000; + ushort pduRef = r_message.PduRef; + const ushort parLg = 0x0008; + const ushort datLg = 0x0000; + const byte serviceId = 0xf0; + const byte reserved = 0x00; + ushort maxCalling = r_message.MaxCalling; + ushort maxCalled = r_message.MaxCalled; + ushort maxPdu = r_message.MaxPdu; + return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, reserved, maxCalling, + maxCalled, maxPdu); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 4; + ushort pduRef = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + pos = 14; + ushort maxCalling = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + ushort maxCalled = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + ushort maxPdu = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + return new EstablishAssociationSimenseOutputStruct(pduRef,maxCalling,maxCalled,maxPdu); + } + } + + public class ReadRequestSimenseInputStruct : InputStruct + { + public ReadRequestSimenseInputStruct(ushort pduRef, SimenseTypeCode getType, string startAddress, ushort getCount, AddressTranslator addressTranslator) + { + PduRef = pduRef; + TypeCode = (byte) getType; + var address = addressTranslator.AddressTranslate(startAddress, true); + Offset = address.Key; + int area = address.Value; + Area = (byte)(area%256); + DbBlock = Area == 0x84 ? (ushort)(area/256) : (ushort)0; + NumberOfElements = getCount; + } + + public ushort PduRef { get; private set; } + public byte TypeCode { get; private set; } + public ushort NumberOfElements { get; private set; } + public ushort DbBlock { get; private set; } + public byte Area { get; private set; } + public int Offset { get; private set; } + } + + public class ReadRequestSimenseOutputStruct : OutputStruct + { + public ReadRequestSimenseOutputStruct(ushort pduRef, SimenseAccessResult accessResult, SimenseDataType dataType, ushort getLength, byte[] value) + { + PduRef = pduRef; + AccessResult = accessResult; + DataType = dataType; + GetLength = getLength; + GetValue = value; + } + + public ushort PduRef { get; private set; } + public SimenseAccessResult AccessResult { get; private set; } + public SimenseDataType DataType { get; private set; } + public ushort GetLength { get; private set; } + public byte[] GetValue { get; private set; } + } + + public class ReadRequestSimenseProtocal : ProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (ReadRequestSimenseInputStruct) message; + const byte protoId = 0x32; + const byte rosctr = 0x01; + const ushort redId = 0x0000; + ushort pduRef = r_message.PduRef; + const ushort parLg = 14; // 参数字节数(2+12的倍数),目前仅为14 + const ushort datLg = 0; // 数据字节数 + const byte serviceId = 0x04; + const byte numberOfVariables = 1; + const byte variableSpec = 0x12; + const byte vAddrLg = 0x0A; + const byte syntaxId = 0x10; + byte type = r_message.TypeCode; + ushort numberOfElements = r_message.NumberOfElements; + ushort dbBlock = r_message.DbBlock; + byte area = r_message.Area; + int offsetBit = r_message.Offset*8; + byte[] offsetBitBytes = ValueHelper.Instance.GetBytes(offsetBit); + return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables + , variableSpec, vAddrLg, syntaxId, type, numberOfElements, dbBlock, area, + offsetBitBytes.Skip(1).ToArray()); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 4; + ushort pduRef = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + pos = 14; + byte accessResult = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte dataType = ValueHelper.Instance.GetByte(messageBytes, ref pos); + ushort length = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + int byteLength = length/8; + var values = new Byte[byteLength]; + Array.Copy(messageBytes, pos, values, 0, byteLength); + return new ReadRequestSimenseOutputStruct(pduRef, (SimenseAccessResult) accessResult, + (SimenseDataType) dataType, length, values); + } + } + + public class WriteRequestSimenseInputStruct : InputStruct + { + public WriteRequestSimenseInputStruct(ushort pduRef, string startAddress, object[] writeValue, AddressTranslator addressTranslator) + { + PduRef = pduRef; + var address = addressTranslator.AddressTranslate(startAddress, true); + Offset = address.Key; + int area = address.Value; + Area = (byte)(area % 256); + DbBlock = Area == 0x84 ? (ushort)(area / 256) : (ushort)0; + WriteValue = writeValue; + } + + public ushort PduRef { get; private set; } + public ushort DbBlock { get; private set; } + public byte Area { get; private set; } + public int Offset { get; private set; } + public object[] WriteValue { get; private set; } + } + + public class WriteRequestSimenseOutputStruct : OutputStruct + { + public WriteRequestSimenseOutputStruct(ushort pduRef, SimenseAccessResult accessResult) + { + PduRef = pduRef; + AccessResult = accessResult; + } + + public ushort PduRef { get; private set; } + public SimenseAccessResult AccessResult {get; private set; } + + } + + public class WriteRequestSimenseProtocal : ProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (WriteRequestSimenseInputStruct) message; + byte[] valueBytes = ValueHelper.Instance.ObjectArrayToByteArray(r_message.WriteValue); + const byte protoId = 0x32; + const byte rosctr = 0x01; + const ushort redId = 0x0000; + ushort pduRef = r_message.PduRef; + const ushort parLg = 14; // 参数字节数(2+12的倍数),目前仅为14 + ushort datLg = (ushort)(4+valueBytes.Length); // 数据字节数 + const byte serviceId = 0x05; + const byte numberOfVariables = 1; + const byte variableSpec = 0x12; + const byte vAddrLg = 0x0A; + const byte syntaxId = 0x10; + const byte typeR = (byte)SimenseTypeCode.Byte; + ushort numberOfElements = (ushort)valueBytes.Length; + ushort dbBlock = r_message.DbBlock; + byte area = r_message.Area; + int offsetBit = r_message.Offset * 8; + byte[] offsetBitBytes = ValueHelper.Instance.GetBytes(offsetBit); + const byte reserved = 0x00; + const byte type = (byte)SimenseDataType.OtherAccess; + ushort numberOfWriteBits = (ushort)(valueBytes.Length*8); + return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables + , variableSpec, vAddrLg, syntaxId, typeR, numberOfElements, dbBlock, area, + offsetBitBytes.Skip(1).ToArray(), reserved, type, numberOfWriteBits, valueBytes); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 4; + ushort pduRef = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + pos = 14; + byte accessResult = ValueHelper.Instance.GetByte(messageBytes, ref pos); + return new WriteRequestSimenseOutputStruct(pduRef, (SimenseAccessResult)accessResult); + } + } + + public class ReadTimeSimenseInputStruct : InputStruct + { + public ReadTimeSimenseInputStruct(ushort pduRef) + { + PduRef = pduRef; + } + + public ushort PduRef { get; private set; } + } + + public class ReadTimeSimenseOutputStruct : OutputStruct + { + public ReadTimeSimenseOutputStruct(ushort pduRef, DateTime dateTime) + { + PduRef = pduRef; + DateTime = dateTime; + } + + public ushort PduRef { get; private set; } + public DateTime DateTime { get; private set; } + } + + public class ReadTimeSimenseProtocal : ProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (ReadTimeSimenseInputStruct) message; + const byte protoId = 0x32; + const byte rosctr = 0x07; + const ushort redId = 0x0000; + ushort pduRef = r_message.PduRef; + const ushort parLg = 8; + const ushort datLg = 4; + const byte serviceId = 0x00; + const byte noVar = 0x01; + const byte varSpc = 0x12; + const byte vAddrLg = 0x04; + const byte synId = 0x11; + const byte classP = 0x47; + const byte id1 = 0x01; + const byte id2 = 0x00; + const byte accRslt = 0x0A; + const byte dType = 0x00; + const ushort length = 0x0000; + return Format(new Byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, noVar, varSpc, vAddrLg, synId, classP, + id1, id2, accRslt, dType, length); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 4; + ushort pduRef = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + pos = 28; + byte year1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte month1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte day1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte hour1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte minute1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte second1 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte second1_10_100 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + byte second1_1000_weekday = ValueHelper.Instance.GetByte(messageBytes, ref pos); + int year = year1/16*10 + year1%16; + int month = month1/16*10 + month1%16; + int day = day1/16*10 + day1%16; + int hour = hour1/16*10 + hour1%16; + int minute = minute1/16*10 + minute1%16; + int second = second1/16*10 + second1%16; + int millisecond = second1_10_100 / 16 * 100 + second1_10_100 % 16 * 10 + second1_1000_weekday / 16; + int weekday = second1_1000_weekday%16; + DateTime dateTime = new DateTime(DateTime.Now.Year/100*100 + year, month, day, hour, minute, second, millisecond); + if (dateTime > DateTime.Now.AddDays(1)) dateTime = dateTime.AddYears(-100); + if (weekday == 0) return new ReadTimeSimenseOutputStruct(pduRef, dateTime); + while (dateTime.DayOfWeek != (DayOfWeek) (weekday - 1)) dateTime = dateTime.AddYears(-100); + return new ReadTimeSimenseOutputStruct(pduRef, dateTime); + } + } + + public class WriteTimeSimenseInputStruct : InputStruct + { + public WriteTimeSimenseInputStruct(ushort pduRef, DateTime dateTime) + { + PduRef = pduRef; + DateTime = dateTime; + } + + public ushort PduRef { get; private set; } + public DateTime DateTime { get; private set; } + } + + public class WriteTimeSimenseOutputStruct : OutputStruct + { + public WriteTimeSimenseOutputStruct(ushort pduRef, byte id2) + { + PduRef = pduRef; + Id2 = id2; + } + + public ushort PduRef { get; private set; } + + public byte Id2 { get; private set; } + } + + public class WriteTimeSimenseProtocal : ProtocalUnit + { + public override byte[] Format(InputStruct message) + { + var r_message = (WriteTimeSimenseInputStruct) message; + const byte protoId = 0x32; + const byte rosctr = 0x07; + const ushort redId = 0x0000; + ushort pduRef = r_message.PduRef; + const ushort parLg = 0x0008; + const ushort datLg = 0x000e; + const byte serviceId = 0x00; + const byte noVar = 0x01; + const byte varSpc = 0x12; + const byte vAddrLg = 0x04; + const byte synId = 0x11; + const byte classP = 0x47; + const byte id1 = 0x02; + const byte id2 = 0x00; + const byte accRslt = 0xFF; + const byte dType = 0x09; + const ushort length = 0x000A; + const ushort todClockStatus = 0x0018; + byte year = (byte) (r_message.DateTime.Year%100/10*16 + r_message.DateTime.Year%10); + byte month = (byte) (r_message.DateTime.Month/10*16 + r_message.DateTime.Month%10); + byte day = (byte) (r_message.DateTime.Day/10*16 + r_message.DateTime.Day%10); + byte hour = (byte) (r_message.DateTime.Hour/10*16 + r_message.DateTime.Hour%10); + byte minute = (byte) (r_message.DateTime.Minute/10*16 + r_message.DateTime.Minute%10); + byte second = (byte) (r_message.DateTime.Second/10*16 + r_message.DateTime.Second%10); + byte dayOfWeek = (byte) (r_message.DateTime.DayOfWeek + 1); + return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, noVar, varSpc, vAddrLg, + synId, classP, id1, id2, accRslt, dType, length, todClockStatus, year, month, day, hour, minute, second, + (byte)0, dayOfWeek); + } + + public override OutputStruct Unformat(byte[] messageBytes, ref int pos) + { + pos = 4; + ushort pduRef = ValueHelper.Instance.GetUShort(messageBytes, ref pos); + pos = 17; + byte id2 = ValueHelper.Instance.GetByte(messageBytes, ref pos); + return new WriteTimeSimenseOutputStruct(pduRef, id2); + } + } + + public class SimenseProtocalErrorException : ProtocalErrorException + { + public int ErrorClass { get; private set; } + public int ErrorCode { get; private set; } + private static readonly Dictionary ProtocalErrorDictionary = new Dictionary() + { + {0x00, "No Error"}, + {0x81, "Error in the application Id of the request"}, + {0x82, "Error in the object definition"}, + {0x83, "No recources available"}, + {0x84, "Error in the sructure of the service request"}, + {0x85, "Error in the communitcation equipment"}, + {0x87, "Access Error"}, + {0xD2, "OVS error"}, + {0xD4, "Diagnostic error"}, + {0xD6, "Protection system error"}, + {0xD8, "BuB error"}, + {0xEF, "Layer 2 specific error"}, + }; + + public SimenseProtocalErrorException(int errCls, int errCod) + : base(ProtocalErrorDictionary[errCls] + " : " + errCod) + { + ErrorClass = errCls; + ErrorCode = errCod; + } + } +} diff --git a/Modbus.Net/ModBus.Net/SimenseProtocalLinkerBytesExtend.cs b/Modbus.Net/ModBus.Net/SimenseProtocalLinkerBytesExtend.cs new file mode 100644 index 0000000..ada714c --- /dev/null +++ b/Modbus.Net/ModBus.Net/SimenseProtocalLinkerBytesExtend.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net +{ + public class SimenseTcpProtocalLinkerBytesExtend : ProtocalLinkerBytesExtend + { + public override byte[] BytesExtend(byte[] content) + { + Array.Copy(new byte[]{0x03,0x00,0x00,0x00,0x02,0xf0,0x80}, 0, content, 0, 7); + Array.Copy(ValueHelper.Instance.GetBytes((ushort)content.Length), 0, content, 2, 2); + return content; + } + + public override byte[] BytesDecact(byte[] content) + { + byte[] newContent = new byte[content.Length - 7]; + Array.Copy(content, 7, newContent, 0, newContent.Length); + return newContent; + } + } +} diff --git a/Modbus.Net/ModBus.Net/SimenseTcpProtocal.cs b/Modbus.Net/ModBus.Net/SimenseTcpProtocal.cs new file mode 100644 index 0000000..08bc32b --- /dev/null +++ b/Modbus.Net/ModBus.Net/SimenseTcpProtocal.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net +{ + public class SimenseTcpProtocal : SimenseProtocal + { + private ushort _taspSrc; + private ushort _tsapDst; + private ushort _maxCalling; + private ushort _maxCalled; + private ushort _maxPdu; + private string _ip; + private int connectTryCount; + + public SimenseTcpProtocal(ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled, ushort maxPdu) : this(tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ConfigurationManager.IP) + { + } + + public SimenseTcpProtocal(ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled, ushort maxPdu, string ip) + { + _taspSrc = tsapSrc; + _tsapDst = tsapDst; + _maxCalling = maxCalling; + _maxCalled = maxCalled; + _maxPdu = maxPdu; + _ip = ip; + connectTryCount = 0; + Connected(); + } + + public override byte[] SendReceive(params object[] content) + { + while (!ProtocalLinker.IsConnected) + { + Connected(); + } + return base.SendReceive(content); + } + + public override OutputStruct SendReceive(ProtocalUnit unit, InputStruct content) + { + if (!ProtocalLinker.IsConnected) + { + if (connectTryCount > 10) return null; + Connected(); + } + return base.SendReceive(unit, content); + } + + private OutputStruct ForceSendReceive(ProtocalUnit unit, InputStruct content) + { + return base.SendReceive(unit, content); + } + + protected void Connected() + { + connectTryCount++; + ProtocalLinker = new SimenseTcpProtocalLinker(_ip); + var inputStruct = new CreateReferenceSimenseInputStruct(0x1a, _taspSrc, _tsapDst); + var outputStruct = + (CreateReferenceSimenseOutputStruct) ForceSendReceive(this[typeof(CreateReferenceSimenseProtocal)], inputStruct); + if (!ProtocalLinker.IsConnected) return; + var inputStruct2 = new EstablishAssociationSimenseInputStruct(0x0101, _maxCalling, _maxCalled, _maxPdu); + var outputStruct2 = (EstablishAssociationSimenseOutputStruct)SendReceive(this[typeof(EstablishAssociationSimenseProtocal)], inputStruct2); + } + } +} diff --git a/Modbus.Net/ModBus.Net/SimenseTcpProtocalLinker.cs b/Modbus.Net/ModBus.Net/SimenseTcpProtocalLinker.cs new file mode 100644 index 0000000..a7a395f --- /dev/null +++ b/Modbus.Net/ModBus.Net/SimenseTcpProtocalLinker.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace ModBus.Net +{ + public class SimenseTcpProtocalLinker : TcpProtocalLinker + { + public override bool CheckRight(byte[] content) + { + switch (content[5]) + { + case 0xd0: + case 0xe0: + return true; + case 0xf0: + switch (content[8]) + { + case 0x03: + if (content[17] == 0x00 && content[18] == 0x00) return true; + throw new SimenseProtocalErrorException(content[17],content[18]); + case 0x07: + if (content[27] == 0x00 && content[28] == 0x00) return true; + throw new SimenseProtocalErrorException(content[27],content[28]); + } + return true; + default: + throw new FormatException(); + } + } + + public SimenseTcpProtocalLinker(string ip) + : base(ip, 102) + { + + } + } +} \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/SimenseUtility.cs b/Modbus.Net/ModBus.Net/SimenseUtility.cs new file mode 100644 index 0000000..d727dae --- /dev/null +++ b/Modbus.Net/ModBus.Net/SimenseUtility.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +public enum SimenseType +{ + Ppi = 0, + Mpi = 1, + Tcp = 2 +} + +namespace ModBus.Net +{ + public class SimenseUtility : BaseUtility + { + private string _connectionString; + + public override string ConnectionString + { + get { return _connectionString; } + set + { + string[] splitStrings = value.Split(','); + switch (splitStrings[1]) + { + case "200": + { + _taspSrc = 0x4d57; + _tsapDst = 0x4d57; + _maxCalling = 0x0001; + _maxCalled = 0x0001; + _maxPdu = 0x03c0; + break; + } + } + _connectionString = splitStrings[0]; + } + } + + private ushort _taspSrc; + private ushort _tsapDst; + private ushort _maxCalling; + private ushort _maxCalled; + private ushort _maxPdu; + + private SimenseType _simenseType; + + public SimenseType ConnectionType + { + get + { + return _simenseType; + } + set + { + _simenseType = value; + switch (_simenseType) + { + case SimenseType.Ppi: + { + throw new NotImplementedException(); + } + case SimenseType.Mpi: + { + throw new NotImplementedException(); + } + case SimenseType.Tcp: + { + Wrapper = ConnectionString == null ? new SimenseTcpProtocal(_taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu) : new SimenseTcpProtocal(_taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu, ConnectionString); + break; + } + } + } + } + + public SimenseUtility(SimenseType connectionType, string connectionString) + { + ConnectionString = connectionString; + ConnectionType = connectionType; + } + + public override void SetConnectionType(int connectionType) + { + ConnectionType = (SimenseType) connectionType; + } + + protected override byte[] GetDatas(byte belongAddress, byte materAddress, string startAddress, int getByteCount) + { + var readRequestSimenseInputStruct = new ReadRequestSimenseInputStruct(0xd3c7, SimenseTypeCode.Byte, startAddress, (ushort)getByteCount, AddressTranslator); + var readRequestSimenseOutputStruct = + (ReadRequestSimenseOutputStruct) + Wrapper.SendReceive(Wrapper[typeof(ReadRequestSimenseProtocal)], readRequestSimenseInputStruct); + return readRequestSimenseOutputStruct.GetValue; + } + + public override bool SetDatas(byte belongAddress, byte materAddress, string startAddress, object[] setContents) + { + var writeRequestSimenseInputStruct = new WriteRequestSimenseInputStruct(0xd3c8, startAddress, setContents, AddressTranslator); + var writeRequestSimenseOutputStruct = + (WriteRequestSimenseOutputStruct) + Wrapper.SendReceive(Wrapper[typeof(WriteRequestSimenseProtocal)], writeRequestSimenseInputStruct); + if (writeRequestSimenseOutputStruct.AccessResult == SimenseAccessResult.NoError) + return true; + else + return false; + } + + public override DateTime GetTime(byte belongAddress) + { + throw new NotImplementedException(); + } + + public override bool SetTime(byte belongAddress, DateTime setTime) + { + throw new NotImplementedException(); + } + } +} diff --git a/Modbus.Net/ModBus.Net/TcpConnector.cs b/Modbus.Net/ModBus.Net/TcpConnector.cs index e700a2e..4bdc014 100644 --- a/Modbus.Net/ModBus.Net/TcpConnector.cs +++ b/Modbus.Net/ModBus.Net/TcpConnector.cs @@ -45,9 +45,9 @@ namespace ModBus.Net b_AsyncReceive = isAsync; } - public bool SocketIsConnect + public override bool IsConnected { - get { return m_socketClient != null ? m_socketClient.Connected : false; } + get { return m_socketClient != null && m_socketClient.Connected; } } public void Dispose() @@ -167,7 +167,7 @@ namespace ModBus.Net try { - if (!SocketIsConnect) + if (!IsConnected) { Connect(); } @@ -255,7 +255,7 @@ namespace ModBus.Net { m_socketClient.Client.Shutdown(SocketShutdown.Both); m_socketClient.Client.Close(); - if (!SocketIsConnect) + if (!IsConnected) { if (SocketErrorShutdown != null) { diff --git a/Modbus.Net/ModBus.Net/TcpProtocalLinker.cs b/Modbus.Net/ModBus.Net/TcpProtocalLinker.cs index d277165..e12f7a2 100644 --- a/Modbus.Net/ModBus.Net/TcpProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/TcpProtocalLinker.cs @@ -10,23 +10,13 @@ namespace ModBus.Net public abstract class TcpProtocalLinker : ProtocalLinker { - protected TcpProtocalLinker() : this(ConfigurationManager.IP) + protected TcpProtocalLinker() : this(ConfigurationManager.IP, int.Parse(ConfigurationManager.Port)) { } - protected TcpProtocalLinker(string ip) + protected TcpProtocalLinker(string ip, int port) { - int port; - //是否启用ConfigurationManager里的Port参数 - if (ConfigurationManager.ResourceManager.GetString("Port") != null && int.TryParse(ConfigurationManager.ResourceManager.GetString("Port"),out port)) - { - - } - else - { - port = 502; - } _baseConnector = new TcpConnector(ip, port, false); } } diff --git a/Modbus.Net/ModBus.Net/ValueHelper.cs b/Modbus.Net/ModBus.Net/ValueHelper.cs index 37cf761..69b43e5 100644 --- a/Modbus.Net/ModBus.Net/ValueHelper.cs +++ b/Modbus.Net/ModBus.Net/ValueHelper.cs @@ -11,6 +11,19 @@ namespace ModBus.Net /// public class ValueHelper { + public Dictionary ByteLength = new Dictionary() + { + {"System.Boolean", 0.125}, + {"System.Byte", 1}, + {"System.Int16", 2}, + {"System.Int32", 4}, + {"System.Int64", 8}, + {"System.UInt16", 2}, + {"System.UInt32", 4}, + {"System.UInt64", 8}, + {"System.Single", 4}, + {"System.Double", 8} + }; protected static bool _littleEndian = false; diff --git a/Modbus.Net/NA200H.UI.Console/Program.cs b/Modbus.Net/NA200H.UI.Console/Program.cs index ff86d3d..d5662b1 100644 --- a/Modbus.Net/NA200H.UI.Console/Program.cs +++ b/Modbus.Net/NA200H.UI.Console/Program.cs @@ -12,9 +12,9 @@ namespace NA200H.UI.ConsoleApp { private static void Main(string[] args) { - string ip = "192.168.3.247"; + string ip = "192.168.3.241"; //先初始化一个协议转换器,这里构造Modbus/Tcp协议。 - BaseProtocal wrapper = new ModbusTcpProtocal(ip); + //BaseProtocal wrapper = new ModbusTcpProtocal(ip); /* try @@ -53,14 +53,14 @@ namespace NA200H.UI.ConsoleApp Console.Read(); Console.Read();*/ - + /* //调用方法二:自动构造 //第一步:先生成一个输入结构体,然后向这个结构体中填写数据 AddressTranslator addressTranslator = new AddressTranslatorNA200H(); - ReadDataInputStruct readCoilStatusInputStruct = new ReadDataInputStruct(0x02, "N1", 0x0a, addressTranslator); + ReadDataModbusInputStruct readCoilStatusInputStruct = new ReadDataModbusInputStruct(0x02, "N1", 0x0a, addressTranslator); //第二步:再生成一个输出结构体,执行相应协议的发送指令,并将输出信息自动转换到输出结构体中 - ReadDataOutputStruct readCoilStatusOutputStruct = (ReadDataOutputStruct)wrapper.SendReceive(wrapper["ReadDataModbusProtocal"], readCoilStatusInputStruct); + ReadDataModbusOutputStruct readCoilStatusOutputStruct = (ReadDataModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(ReadDataModbusProtocal)], readCoilStatusInputStruct); //第三步:读取这个输出结构体的信息。 bool[] array = ValueHelper.Instance.ObjectArrayToDestinationArray( @@ -74,8 +74,8 @@ namespace NA200H.UI.ConsoleApp Console.Read(); Console.Read(); - ReadDataInputStruct readHoldRegisterInputStruct = new ReadDataInputStruct(0x02, "NW1", 4, addressTranslator); - ReadDataOutputStruct readHoldRegisterOutputStruct = (ReadDataOutputStruct)wrapper.SendReceive(wrapper["ReadDataModbusProtocal"], readHoldRegisterInputStruct); + ReadDataModbusInputStruct readHoldRegisterInputStruct = new ReadDataModbusInputStruct(0x02, "NW1", 4, addressTranslator); + ReadDataModbusOutputStruct readHoldRegisterOutputStruct = (ReadDataModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(ReadDataModbusProtocal)], readHoldRegisterInputStruct); ushort[] array2 = ValueHelper.Instance.ObjectArrayToDestinationArray( ValueHelper.Instance.ByteArrayToObjectArray(readHoldRegisterOutputStruct.DataValue, @@ -88,35 +88,77 @@ namespace NA200H.UI.ConsoleApp Console.Read(); Console.Read(); - WriteDataInputStruct writeMultiCoilInputStruct = new WriteDataInputStruct(0x02, "Q20", new object[] { true, false, true, true, false, false, true, true, true, false }, addressTranslator); - WriteDataOutputStruct writeMultiCoilOutputStruct = (WriteDataOutputStruct)wrapper.SendReceive(wrapper["WriteDataModbusProtocal"], writeMultiCoilInputStruct); + WriteDataModbusInputStruct writeMultiCoilInputStruct = new WriteDataModbusInputStruct(0x02, "Q20", new object[] { true, false, true, true, false, false, true, true, true, false }, addressTranslator); + WriteDataModbusOutputStruct writeMultiCoilOutputStruct = (WriteDataModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(WriteDataModbusProtocal)], writeMultiCoilInputStruct); Console.WriteLine(writeMultiCoilOutputStruct.StartAddress); Console.WriteLine(writeMultiCoilOutputStruct.WriteCount); Console.WriteLine(); Console.Read(); Console.Read(); - WriteDataInputStruct writeMultiRegisterInputStruct = new WriteDataInputStruct(0x02, "NW1", new object[] { (ushort)25, (ushort)18, (ushort)17 }, addressTranslator); - WriteDataOutputStruct writeMultiRegisterOutputStruct = (WriteDataOutputStruct)wrapper.SendReceive(wrapper["WriteDataModbusProtocal"], writeMultiRegisterInputStruct); + WriteDataModbusInputStruct writeMultiRegisterInputStruct = new WriteDataModbusInputStruct(0x02, "NW1", new object[] { (ushort)25, (ushort)18, (ushort)17 }, addressTranslator); + WriteDataModbusOutputStruct writeMultiRegisterOutputStruct = (WriteDataModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(WriteDataModbusProtocal)], writeMultiRegisterInputStruct); Console.WriteLine(writeMultiRegisterOutputStruct.StartAddress); Console.WriteLine(writeMultiRegisterOutputStruct.WriteCount); Console.WriteLine(); Console.Read(); Console.Read(); - GetSystemTimeInputStruct getSystemTimeInputStruct = new GetSystemTimeInputStruct(0x02); - GetSystemTimeOutputStruct getSystemTimeOutputStruct = (GetSystemTimeOutputStruct)wrapper.SendReceive(wrapper["GetSystemTimeModbusProtocal"], getSystemTimeInputStruct); + GetSystemTimeModbusInputStruct getSystemTimeInputStruct = new GetSystemTimeModbusInputStruct(0x02); + GetSystemTimeModbusOutputStruct getSystemTimeOutputStruct = (GetSystemTimeModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(GetSystemTimeModbusProtocal)], getSystemTimeInputStruct); Console.WriteLine(getSystemTimeOutputStruct.Time); Console.Read(); Console.Read(); - SetSystemTimeInputStruct setSystemTimeInputStruct = new SetSystemTimeInputStruct(0x02, DateTime.Now); - SetSystemTimeOutputStruct setSystemTimeOutputStruct = (SetSystemTimeOutputStruct)wrapper.SendReceive(wrapper["SetSystemTimeModbusProtocal"], setSystemTimeInputStruct); + SetSystemTimeModbusInputStruct setSystemTimeInputStruct = new SetSystemTimeModbusInputStruct(0x02, DateTime.Now); + SetSystemTimeModbusOutputStruct setSystemTimeOutputStruct = (SetSystemTimeModbusOutputStruct)wrapper.SendReceive(wrapper[typeof(SetSystemTimeModbusProtocal)], setSystemTimeInputStruct); Console.WriteLine(setSystemTimeOutputStruct.StartAddress); Console.WriteLine(setSystemTimeOutputStruct.WriteCount); Console.Read(); Console.Read(); - + */ + + BaseProtocal wrapper = new SimenseTcpProtocal(0x4d57, 0x4d57, 0x0001, 0x0001, 0x03c0, ip); + if (!wrapper.ProtocalLinker.IsConnected) return; + AddressTranslator addressTranslator = new AddressTranslatorSimense(); + + var readRequestSimenseInputStruct = new ReadRequestSimenseInputStruct(0xaacc, SimenseTypeCode.Byte, "V0", 4, addressTranslator); + var readRequestSimenseOutputStruct = + (ReadRequestSimenseOutputStruct) + wrapper.SendReceive(wrapper[typeof(ReadRequestSimenseProtocal)], readRequestSimenseInputStruct); + ushort[] array = + ValueHelper.Instance.ObjectArrayToDestinationArray( + ValueHelper.Instance.ByteArrayToObjectArray(readRequestSimenseOutputStruct.GetValue, + new KeyValuePair(typeof (ushort), 2))); + for (int i = 0; i < array.Length; i++) + { + Console.WriteLine(array[i]); + } + Console.Read(); + Console.Read(); + + var writeRequestSimenseInputStruct = new WriteRequestSimenseInputStruct(0xaadd, "V100", + new object[] { (ushort)280, (ushort)12, (ushort)56, (ushort)72, (ushort)88, (ushort)525, (ushort)477, (ushort)151, (ushort)52 }, addressTranslator); + var writeRequestSimenseOutputStruct = + (WriteRequestSimenseOutputStruct) + wrapper.SendReceive(wrapper[typeof(WriteRequestSimenseProtocal)], writeRequestSimenseInputStruct); + Console.WriteLine(writeRequestSimenseOutputStruct.AccessResult.ToString()); + Console.Read(); + Console.Read(); + + var readTimeSimenseInputStruct = new ReadTimeSimenseInputStruct(0xaaee); + var readTimeSimenseOutputStruct = + (ReadTimeSimenseOutputStruct) + wrapper.SendReceive(wrapper[typeof(ReadTimeSimenseProtocal)], readTimeSimenseInputStruct); + Console.WriteLine(readTimeSimenseOutputStruct.DateTime); + Console.Read(); + Console.Read(); + + var writeTimeSimenseInputStruct = new WriteTimeSimenseInputStruct(0xaaee, DateTime.Now); + var writeTimeSimenseOutputStruct = + (WriteTimeSimenseOutputStruct) + wrapper.SendReceive(wrapper[typeof(WriteTimeSimenseProtocal)], writeTimeSimenseInputStruct); + Console.WriteLine(writeTimeSimenseOutputStruct.Id2); } } } diff --git a/Modbus.Net/NA200H.UI.WPF/3ADD.mwp b/Modbus.Net/NA200H.UI.WPF/3ADD.mwp index afccef2ba621b87c563f127fbd44dcbd5bcc66a8..18ee1573ffc908846e6f9e5061f8fe08bfa91da9 100644 GIT binary patch delta 22674 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 diff --git a/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs b/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs index 9d361e2..c85dbdc 100644 --- a/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs +++ b/Modbus.Net/NA200H.UI.WPF/MainWindow.xaml.cs @@ -12,7 +12,7 @@ namespace NA200H.UI.WPF /// public partial class MainWindow : Window { - private ModbusUtility utility; + private BaseUtility utility; public MainWindow() { InitializeComponent(); @@ -20,14 +20,13 @@ namespace NA200H.UI.WPF private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) { - utility = new ModbusUtility((int) ModbusType.Tcp, "192.168.3.247"); - utility.AddressTranslator = new AddressTranslatorNA200H(); - //byte[] getNum = utility.GetDatas(0x02, "03:10000", 8); - byte[] getNum = utility.GetDatas(0x02, "NW1", 8); - object[] getNumObjects = - ValueHelper.Instance.ByteArrayToObjectArray(getNum, - new List>(){{new KeyValuePair(typeof(ushort), 4)}}); - ushort[] getNumUshorts = ValueHelper.Instance.ObjectArrayToDestinationArray(getNumObjects); + //utility = new ModbusUtility(ModbusType.Tcp, "192.168.3.247"); + //utility.AddressTranslator = new AddressTranslatorNA200H(); + //object[] getNum = utility.GetDatas(0x02, 0x00, "NW1", new KeyValuePair(typeof(ushort), 4)); + utility = new SimenseUtility(SimenseType.Tcp, "192.168.3.241,200"); + utility.AddressTranslator = new AddressTranslatorSimense(); + object[] getNum = utility.GetDatas(0x02, 0x00, "V1", new KeyValuePair(typeof(ushort), 4)); + ushort[] getNumUshorts = ValueHelper.Instance.ObjectArrayToDestinationArray(getNum); SetValue(getNumUshorts); } @@ -45,14 +44,12 @@ namespace NA200H.UI.WPF ushort.TryParse(Add1.Text, out add1); ushort.TryParse(Add2.Text, out add2); ushort.TryParse(Add3.Text, out add3); - //utility.SetDatas(0x02, "16:10000", new object[] {add1, add2, add3}); - utility.SetDatas(0x02, "NW1", new object[] { add1, add2, add3 }); + //utility.SetDatas(0x02, 0x00, "NW1", new object[] { add1, add2, add3 }); + utility.SetDatas(0x02, 0x00, "V1", new object[] { add1, add2, add3 }); Thread.Sleep(100); - //byte[] getNum = utility.GetDatas(0x02, "03:10000", 8); - byte[] getNum = utility.GetDatas(0x02, "NW1", 8); - object[] getNumObjects = - ValueHelper.Instance.ByteArrayToObjectArray(getNum, new KeyValuePair(typeof(ushort), 4)); - ushort[] getNumUshorts = ValueHelper.Instance.ObjectArrayToDestinationArray(getNumObjects); + //object[] getNum = utility.GetDatas(0x02, 0x00, "NW1", new KeyValuePair(typeof(ushort), 4)); + object[] getNum = utility.GetDatas(0x02, 0x00, "V1", new KeyValuePair(typeof(ushort), 4)); + ushort[] getNumUshorts = ValueHelper.Instance.ObjectArrayToDestinationArray(getNum); SetValue(getNumUshorts); } }