From f9a0b99bf578af331c7d489104e3a602a4dbc7d4 Mon Sep 17 00:00:00 2001 From: richburgess Date: Sun, 12 Sep 2021 16:21:01 -0400 Subject: [PATCH] Created new Standard2.1 project and pulled in client from .NET 4.0 project for full features. --- EasyModbus.sln | 52 +- .../EasyModbus.StoreLogData.cs | 120 + .../EasyModbus_Standard2.1.csproj | 12 + .../Exceptions/Exceptions.cs | 211 ++ .../EasyModbus.ModbusClient.Core.cs | 2314 +++++++++++++++++ .../EasyModbus.ModbusClient.Helpers.cs | 506 ++++ .../EasyModbus.ModbusClient.Protocol.cs | 189 ++ 7 files changed, 3403 insertions(+), 1 deletion(-) create mode 100644 EasyModbus_Standard2.1/EasyModbus.StoreLogData.cs create mode 100644 EasyModbus_Standard2.1/EasyModbus_Standard2.1.csproj create mode 100644 EasyModbus_Standard2.1/Exceptions/Exceptions.cs create mode 100644 EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Core.cs create mode 100644 EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Helpers.cs create mode 100644 EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Protocol.cs diff --git a/EasyModbus.sln b/EasyModbus.sln index 2ec15b3..bc7038f 100644 --- a/EasyModbus.sln +++ b/EasyModbus.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppStd", "ConsoleApp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyModbus_V5.0", "EasyModbus_NET5\EasyModbus_V5.0.csproj", "{83AFFC60-BC95-46B1-861F-B1F80270FBFA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyModbus_Standard2.1", "EasyModbus_Standard2.1\EasyModbus_Standard2.1.csproj", "{B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -331,12 +333,60 @@ Global {83AFFC60-BC95-46B1-861F-B1F80270FBFA}.Release|x64.Build.0 = Release|Any CPU {83AFFC60-BC95-46B1-861F-B1F80270FBFA}.Release|x86.ActiveCfg = Release|Any CPU {83AFFC60-BC95-46B1-861F-B1F80270FBFA}.Release|x86.Build.0 = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|ARM.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|x64.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|x64.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Debug|x86.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|Any CPU.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|Any CPU.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|ARM.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|ARM.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|x64.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|x64.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|x86.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial|x86.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|Any CPU.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|Any CPU.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|ARM.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|ARM.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|x64.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|x64.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|x86.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial1|x86.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|Any CPU.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|Any CPU.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|ARM.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|ARM.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|x64.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|x64.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|x86.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial2|x86.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|Any CPU.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|Any CPU.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|ARM.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|ARM.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|x64.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|x64.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|x86.ActiveCfg = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.DebugCommercial3|x86.Build.0 = Debug|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|Any CPU.Build.0 = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|ARM.ActiveCfg = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|ARM.Build.0 = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|x64.ActiveCfg = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|x64.Build.0 = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|x86.ActiveCfg = Release|Any CPU + {B0E8ADB4-6599-4440-92DF-12DA4E36C6BD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {7628B1C9-8DDB-4DBD-A71D-D369A4A166DE} VisualSVNWorkingCopyRoot = . + SolutionGuid = {7628B1C9-8DDB-4DBD-A71D-D369A4A166DE} EndGlobalSection EndGlobal diff --git a/EasyModbus_Standard2.1/EasyModbus.StoreLogData.cs b/EasyModbus_Standard2.1/EasyModbus.StoreLogData.cs new file mode 100644 index 0000000..3345038 --- /dev/null +++ b/EasyModbus_Standard2.1/EasyModbus.StoreLogData.cs @@ -0,0 +1,120 @@ +/* +Copyright (c) 2018-2020 Rossmann-Engineering +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software +and associated documentation files (the "Software"), +to deal in the Software without restriction, +including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission +notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace EasyModbus +{ + /// + /// Store Log-Data in a File + /// + public sealed class StoreLogData + { + private String filename = null; + private static volatile StoreLogData instance; + private static object syncObject = new Object(); + + /// + /// Private constructor; Ensures the access of the class only via "instance" + /// + private StoreLogData() + { + } + + /// + /// Returns the instance of the class (singleton) + /// + /// instance (Singleton) + public static StoreLogData Instance + { + get + { + if (instance == null) + { + lock (syncObject) + { + if (instance == null) + instance = new StoreLogData(); + } + } + + return instance; + } + } + + /// + /// Store message in Log-File + /// + /// Message to append to the Log-File + public void Store(String message) + { + if (this.filename == null) + return; + + using (System.IO.StreamWriter file = + new System.IO.StreamWriter(Filename, true)) + { + file.WriteLine(message); + } + } + + /// + /// Store message in Log-File including Timestamp + /// + /// Message to append to the Log-File + /// Timestamp to add to the same Row + public void Store(String message, DateTime timestamp) + { + try + { + using (System.IO.StreamWriter file = + new System.IO.StreamWriter(Filename, true)) + { + file.WriteLine(timestamp.ToString("dd.MM.yyyy H:mm:ss.ff ") + message); + } + } + catch (Exception e) + { + + } + } + + /// + /// Gets or Sets the Filename to Store Strings in a File + /// + public string Filename + { + get + { + return filename; + } + set + { + filename = value; + } + } + } +} diff --git a/EasyModbus_Standard2.1/EasyModbus_Standard2.1.csproj b/EasyModbus_Standard2.1/EasyModbus_Standard2.1.csproj new file mode 100644 index 0000000..ea2a724 --- /dev/null +++ b/EasyModbus_Standard2.1/EasyModbus_Standard2.1.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + EasyModbus_Standard2._1 + + + + + + + diff --git a/EasyModbus_Standard2.1/Exceptions/Exceptions.cs b/EasyModbus_Standard2.1/Exceptions/Exceptions.cs new file mode 100644 index 0000000..8d1db4f --- /dev/null +++ b/EasyModbus_Standard2.1/Exceptions/Exceptions.cs @@ -0,0 +1,211 @@ +/* +Copyright (c) 2018-2020 Rossmann-Engineering +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software +and associated documentation files (the "Software"), +to deal in the Software without restriction, +including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission +notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +using System; +using System.Runtime.Serialization; + +namespace EasyModbus.Exceptions +{ + /// + /// Exception to be thrown if serial port is not opened + /// + public class SerialPortNotOpenedException : ModbusException + { + public SerialPortNotOpenedException() + : base() + { + } + + public SerialPortNotOpenedException(string message) + : base(message) + { + } + + public SerialPortNotOpenedException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected SerialPortNotOpenedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if Connection to Modbus device failed + /// + public class ConnectionException : ModbusException + { + public ConnectionException() + : base() + { + } + + public ConnectionException(string message) + : base(message) + { + } + + public ConnectionException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected ConnectionException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if Modbus Server returns error code "Function code not supported" + /// + public class FunctionCodeNotSupportedException : ModbusException + { + public FunctionCodeNotSupportedException() + : base() + { + } + + public FunctionCodeNotSupportedException(string message) + : base(message) + { + } + + public FunctionCodeNotSupportedException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected FunctionCodeNotSupportedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if Modbus Server returns error code "quantity invalid" + /// + public class QuantityInvalidException : ModbusException + { + public QuantityInvalidException() + : base() + { + } + + public QuantityInvalidException(string message) + : base(message) + { + } + + public QuantityInvalidException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected QuantityInvalidException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if Modbus Server returns error code "starting adddress and quantity invalid" + /// + public class StartingAddressInvalidException : ModbusException + { + public StartingAddressInvalidException() + : base() + { + } + + public StartingAddressInvalidException(string message) + : base(message) + { + } + + public StartingAddressInvalidException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected StartingAddressInvalidException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if Modbus Server returns error code "Function Code not executed (0x04)" + /// + public class ModbusException : Exception + { + public ModbusException() + : base() + { + } + + public ModbusException(string message) + : base(message) + { + } + + public ModbusException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected ModbusException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// Exception to be thrown if CRC Check failed + /// + public class CRCCheckFailedException : ModbusException + { + public CRCCheckFailedException() + : base() + { + } + + public CRCCheckFailedException(string message) + : base(message) + { + } + + public CRCCheckFailedException(string message, Exception innerException) + : base(message, innerException) + { + } + + protected CRCCheckFailedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + +} diff --git a/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Core.cs b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Core.cs new file mode 100644 index 0000000..a386087 --- /dev/null +++ b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Core.cs @@ -0,0 +1,2314 @@ +/* +Copyright (c) 2018-2020 Rossmann-Engineering +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software +and associated documentation files (the "Software"), +to deal in the Software without restriction, +including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission +notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Net.Sockets; +using System.Net; +using System.IO.Ports; +using System.Reflection; +using System.Text; +using System.Collections.Generic; + +namespace EasyModbus +{ + /// + /// Implements a ModbusClient. + /// + public partial class ModbusClient + { + private bool debug=false; + private TcpClient tcpClient; + private string ipAddress = "127.0.0.1"; + private int port = 502; + private uint transactionIdentifierInternal = 0; + private byte [] transactionIdentifier = new byte[2]; + private byte [] protocolIdentifier = new byte[2]; + private byte[] crc = new byte[2]; + private byte [] length = new byte[2]; + private byte unitIdentifier = 0x01; + private byte functionCode; + private byte [] startingAddress = new byte[2]; + private byte [] quantity = new byte[2]; + private bool udpFlag = false; + private int portOut; + private int baudRate = 9600; + private int connectTimeout = 1000; + public byte[] receiveData; + public byte[] sendData; + private SerialPort serialport; + private Parity parity = Parity.Even; + private StopBits stopBits = StopBits.One; + private bool connected = false; + public int NumberOfRetries { get; set; } = 3; + private int countRetries = 0; + + private bool dataReceived = false; + private bool receiveActive = false; + private byte[] readBuffer = new byte[256]; + private int bytesToRead = 0; + + public delegate void ReceiveDataChangedHandler(object sender); + public event ReceiveDataChangedHandler ReceiveDataChanged; + + public delegate void SendDataChangedHandler(object sender); + public event SendDataChangedHandler SendDataChanged; + + public delegate void ConnectedChangedHandler(object sender); + public event ConnectedChangedHandler ConnectedChanged; + + NetworkStream stream; + + /// + /// Constructor which determines the Master ip-address and the Master Port. + /// + /// IP-Address of the Master device + /// Listening port of the Master device (should be 502) + public ModbusClient(string ipAddress, int port) + { + if (debug) StoreLogData.Instance.Store("EasyModbus library initialized for Modbus-TCP, IPAddress: " + ipAddress + ", Port: "+port ,System.DateTime.Now); +#if (!COMMERCIAL) + Console.WriteLine("EasyModbus Client Library Version: " + Assembly.GetExecutingAssembly().GetName().Version.ToString()); + Console.WriteLine("Copyright (c) Stefan Rossmann Engineering Solutions"); + Console.WriteLine(); +#endif + this.ipAddress = ipAddress; + this.port = port; + } + + /// + /// Constructor which determines the Serial-Port + /// + /// Serial-Port Name e.G. "COM1" + public ModbusClient(string serialPort) + { + if (debug) StoreLogData.Instance.Store("EasyModbus library initialized for Modbus-RTU, COM-Port: " + serialPort ,System.DateTime.Now); +#if (!COMMERCIAL) + Console.WriteLine("EasyModbus Client Library Version: " + Assembly.GetExecutingAssembly().GetName().Version.ToString()); + Console.WriteLine("Copyright (c) Stefan Rossmann Engineering Solutions"); + Console.WriteLine(); +#endif + this.serialport = new SerialPort(); + serialport.PortName = serialPort; + serialport.BaudRate = baudRate; + serialport.Parity = parity; + serialport.StopBits = stopBits; + serialport.WriteTimeout = 10000; + serialport.ReadTimeout = connectTimeout; + + serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + } + + /// + /// Parameterless constructor + /// + public ModbusClient() + { + if (debug) StoreLogData.Instance.Store("EasyModbus library initialized for Modbus-TCP" ,System.DateTime.Now); +#if (!COMMERCIAL) + Console.WriteLine("EasyModbus Client Library Version: " + Assembly.GetExecutingAssembly().GetName().Version.ToString()); + Console.WriteLine("Copyright (c) Stefan Rossmann Engineering Solutions"); + Console.WriteLine(); +#endif + } + + /// + /// Establish connection to Master device in case of Modbus TCP. Opens COM-Port in case of Modbus RTU + /// + public void Connect() + { + if (serialport != null) + { + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("Open Serial port " + serialport.PortName,System.DateTime.Now); + serialport.BaudRate = baudRate; + serialport.Parity = parity; + serialport.StopBits = stopBits; + serialport.WriteTimeout = 10000; + serialport.ReadTimeout = connectTimeout; + serialport.Open(); + connected = true; + + + } + if (ConnectedChanged != null) + try + { + ConnectedChanged(this); + } + catch + { + + } + return; + } + if (!udpFlag) + { + if (debug) StoreLogData.Instance.Store("Open TCP-Socket, IP-Address: " + ipAddress + ", Port: " + port, System.DateTime.Now); + tcpClient = new TcpClient(); + var result = tcpClient.BeginConnect(ipAddress, port, null, null); + var success = result.AsyncWaitHandle.WaitOne(connectTimeout); + if (!success) + { + throw new EasyModbus.Exceptions.ConnectionException("connection timed out"); + } + tcpClient.EndConnect(result); + + //tcpClient = new TcpClient(ipAddress, port); + stream = tcpClient.GetStream(); + stream.ReadTimeout = connectTimeout; + connected = true; + } + else + { + tcpClient = new TcpClient(); + connected = true; + } + if (ConnectedChanged != null) + try + { + ConnectedChanged(this); + } + catch + { + + } + } + + /// + /// Establish connection to Master device in case of Modbus TCP. + /// + public void Connect(string ipAddress, int port) + { + if (!udpFlag) + { + if (debug) StoreLogData.Instance.Store("Open TCP-Socket, IP-Address: " + ipAddress + ", Port: " + port, System.DateTime.Now); + tcpClient = new TcpClient(); + var result = tcpClient.BeginConnect(ipAddress, port, null, null); + var success = result.AsyncWaitHandle.WaitOne(connectTimeout); + if (!success) + { + throw new EasyModbus.Exceptions.ConnectionException("connection timed out"); + } + tcpClient.EndConnect(result); + + //tcpClient = new TcpClient(ipAddress, port); + stream = tcpClient.GetStream(); + stream.ReadTimeout = connectTimeout; + connected = true; + } + else + { + tcpClient = new TcpClient(); + connected = true; + } + + if (ConnectedChanged != null) + ConnectedChanged(this); + } + + private void DataReceivedHandler(object sender, + SerialDataReceivedEventArgs e) + { + serialport.DataReceived -= DataReceivedHandler; + + //while (receiveActive | dataReceived) + // System.Threading.Thread.Sleep(10); + receiveActive = true; + + const long ticksWait = TimeSpan.TicksPerMillisecond * 2000;//((40*10000000) / this.baudRate); + + + SerialPort sp = (SerialPort)sender; + if (bytesToRead == 0) + { + sp.DiscardInBuffer(); + receiveActive = false; + serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + return; + } + readBuffer = new byte[256]; + int numbytes=0; + int actualPositionToRead = 0; + DateTime dateTimeLastRead = DateTime.Now; + do{ + try { + dateTimeLastRead = DateTime.Now; + while ((sp.BytesToRead) == 0) + { + System.Threading.Thread.Sleep(10); + if ((DateTime.Now.Ticks - dateTimeLastRead.Ticks) > ticksWait) + break; + } + numbytes=sp.BytesToRead; + + + byte[] rxbytearray = new byte[numbytes]; + sp.Read(rxbytearray, 0, numbytes); + Array.Copy(rxbytearray,0, readBuffer,actualPositionToRead, (actualPositionToRead + rxbytearray.Length) <= bytesToRead ? rxbytearray.Length : bytesToRead - actualPositionToRead); + + actualPositionToRead = actualPositionToRead + rxbytearray.Length; + + } + catch (Exception){ + + } + + if (bytesToRead <= actualPositionToRead) + break; + + if (DetectValidModbusFrame(readBuffer, (actualPositionToRead < readBuffer.Length) ? actualPositionToRead : readBuffer.Length) | bytesToRead <= actualPositionToRead) + break; + } + while ((DateTime.Now.Ticks - dateTimeLastRead.Ticks) < ticksWait) ; + + //10.000 Ticks in 1 ms + + receiveData = new byte[actualPositionToRead]; + Array.Copy(readBuffer, 0, receiveData, 0, (actualPositionToRead < readBuffer.Length) ? actualPositionToRead: readBuffer.Length); + if (debug) StoreLogData.Instance.Store("Received Serial-Data: "+BitConverter.ToString(readBuffer) ,System.DateTime.Now); + bytesToRead = 0; + + + + + dataReceived = true; + receiveActive = false; + serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + if (ReceiveDataChanged != null) + { + + ReceiveDataChanged(this); + + } + + //sp.DiscardInBuffer(); + } + + public static bool DetectValidModbusFrame(byte[] readBuffer, int length) + { + // minimum length 6 bytes + if (length < 6) + return false; + //SlaveID correct + if ((readBuffer[0] < 1) | (readBuffer[0] > 247)) + return false; + //CRC correct? + byte[] crc = new byte[2]; + crc = BitConverter.GetBytes(calculateCRC(readBuffer, (ushort)(length-2), 0)); + if (crc[0] != readBuffer[length-2] | crc[1] != readBuffer[length-1]) + return false; + return true; + } + + + + /// + /// Read Discrete Inputs from Server device (FC2). + /// + /// First discrete input to read + /// Number of discrete Inputs to read + /// Boolean Array which contains the discrete Inputs + public bool[] ReadDiscreteInputs(int startingAddress, int quantity) + { + if (debug) StoreLogData.Instance.Store("FC2 (Read Discrete Inputs from Master device), StartingAddress: "+ startingAddress+", Quantity: " +quantity, System.DateTime.Now); + transactionIdentifierInternal ++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport==null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + if (startingAddress > 65535 | quantity >2000) + { + if (debug) StoreLogData.Instance.Store("ArgumentException Throwed", System.DateTime.Now); + throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 2000"); + } + bool[] response; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int) 0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x02; + this.startingAddress = BitConverter.GetBytes(startingAddress); + this.quantity = BitConverter.GetBytes(quantity); + Byte[] data = new byte[] + { + this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + this.quantity[1], + this.quantity[0], + this.crc[0], + this.crc[1] + }; + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + + if (serialport != null) + { + dataReceived = false; + if (quantity % 8 == 0) + bytesToRead = 5 + quantity / 8; + else + bytesToRead = 6 + quantity / 8; + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + + + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x82 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x82 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x82 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x82 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data[8]+3), 6)); + if ((crc[0] != data[data[8] + 9] | crc[1] != data[data[8] + 10]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + return ReadDiscreteInputs(startingAddress, quantity); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + } + else + { + countRetries++; + return ReadDiscreteInputs(startingAddress, quantity); + } + } + } + response = new bool[quantity]; + for (int i = 0; i < quantity; i++) + { + int intData = data[9+i/8]; + int mask = Convert.ToInt32(Math.Pow(2, (i%8))); + response[i] = Convert.ToBoolean((intData & mask)/mask); + } + return (response); + } + + + /// + /// Read Coils from Server device (FC1). + /// + /// First coil to read + /// Numer of coils to read + /// Boolean Array which contains the coils + public bool[] ReadCoils(int startingAddress, int quantity) + { + if (debug) StoreLogData.Instance.Store("FC1 (Read Coils from Master device), StartingAddress: "+ startingAddress+", Quantity: " +quantity, System.DateTime.Now); + transactionIdentifierInternal++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + if (startingAddress > 65535 | quantity >2000) + { + if (debug) StoreLogData.Instance.Store("ArgumentException Throwed", System.DateTime.Now); + throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 2000"); + } + bool[] response; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int) 0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x01; + this.startingAddress = BitConverter.GetBytes(startingAddress); + this.quantity = BitConverter.GetBytes(quantity); + Byte[] data = new byte[]{ + this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + this.quantity[1], + this.quantity[0], + this.crc[0], + this.crc[1] + }; + + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + if (serialport != null) + { + dataReceived = false; + if (quantity % 8 == 0) + bytesToRead = 5 + quantity/8; + else + bytesToRead = 6 + quantity/8; + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send MocbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x81 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x81 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x81 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x81 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data[8]+3), 6)); + if ((crc[0] != data[data[8]+9] | crc[1] != data[data[8]+10]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + return ReadCoils(startingAddress, quantity); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + } + else + { + countRetries++; + return ReadCoils(startingAddress, quantity); + } + } + } + response = new bool[quantity]; + for (int i = 0; i < quantity; i++) + { + int intData = data[9+i/8]; + int mask = Convert.ToInt32(Math.Pow(2, (i%8))); + response[i] = Convert.ToBoolean((intData & mask)/mask); + } + return (response); + } + + + /// + /// Read Holding Registers from Master device (FC3). + /// + /// First holding register to be read + /// Number of holding registers to be read + /// Int Array which contains the holding registers + public int[] ReadHoldingRegisters(int startingAddress, int quantity) + { + if (debug) StoreLogData.Instance.Store("FC3 (Read Holding Registers from Master device), StartingAddress: "+ startingAddress+", Quantity: " +quantity, System.DateTime.Now); + transactionIdentifierInternal++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + if (startingAddress > 65535 | quantity >125) + { + if (debug) StoreLogData.Instance.Store("ArgumentException Throwed", System.DateTime.Now); + throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 125"); + } + int[] response; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int) 0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x03; + this.startingAddress = BitConverter.GetBytes(startingAddress); + this.quantity = BitConverter.GetBytes(quantity); + Byte[] data = new byte[]{ this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + this.quantity[1], + this.quantity[0], + this.crc[0], + this.crc[1] + }; + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 5 + 2 * quantity; +// serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[256]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x83 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x83 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x83 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x83 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data[8]+3), 6)); + if ((crc[0] != data[data[8]+9] | crc[1] != data[data[8]+10])& dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + return ReadHoldingRegisters(startingAddress, quantity); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + } + else + { + countRetries++; + return ReadHoldingRegisters(startingAddress, quantity); + } + + + } + } + response = new int[quantity]; + for (int i = 0; i < quantity; i++) + { + byte lowByte; + byte highByte; + highByte = data[9+i*2]; + lowByte = data[9+i*2+1]; + + data[9+i*2] = lowByte; + data[9+i*2+1] = highByte; + + response[i] = BitConverter.ToInt16(data,(9+i*2)); + } + return (response); + } + + + + /// + /// Read Input Registers from Master device (FC4). + /// + /// First input register to be read + /// Number of input registers to be read + /// Int Array which contains the input registers + public int[] ReadInputRegisters(int startingAddress, int quantity) + { + + if (debug) StoreLogData.Instance.Store("FC4 (Read Input Registers from Master device), StartingAddress: "+ startingAddress+", Quantity: " +quantity, System.DateTime.Now); + transactionIdentifierInternal++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + if (startingAddress > 65535 | quantity >125) + { + if (debug) StoreLogData.Instance.Store("ArgumentException Throwed", System.DateTime.Now); + throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 125"); + } + int[] response; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int) 0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x04; + this.startingAddress = BitConverter.GetBytes(startingAddress); + this.quantity = BitConverter.GetBytes(quantity); + Byte[] data = new byte[]{ this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + this.quantity[1], + this.quantity[0], + this.crc[0], + this.crc[1] + }; + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 5 + 2 * quantity; + + + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + + } + } + if (data[7] == 0x84 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x84 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x84 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x84 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data[8]+3), 6)); + if ((crc[0] != data[data[8]+9] | crc[1] != data[data[8]+10]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + return ReadInputRegisters(startingAddress, quantity); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + + } + else + { + countRetries++; + return ReadInputRegisters(startingAddress, quantity); + } + + } + } + response = new int[quantity]; + for (int i = 0; i < quantity; i++) + { + byte lowByte; + byte highByte; + highByte = data[9+i*2]; + lowByte = data[9+i*2+1]; + + data[9+i*2] = lowByte; + data[9+i*2+1] = highByte; + + response[i] = BitConverter.ToInt16(data,(9+i*2)); + } + return (response); + } + + + /// + /// Write single Coil to Master device (FC5). + /// + /// Coil to be written + /// Coil Value to be written + public void WriteSingleCoil(int startingAddress, bool value) + { + + if (debug) StoreLogData.Instance.Store("FC5 (Write single coil to Master device), StartingAddress: "+ startingAddress+", Value: " + value, System.DateTime.Now); + transactionIdentifierInternal++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + byte[] coilValue = new byte[2]; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int)0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x05; + this.startingAddress = BitConverter.GetBytes(startingAddress); + if (value == true) + { + coilValue = BitConverter.GetBytes((int)0xFF00); + } + else + { + coilValue = BitConverter.GetBytes((int)0x0000); + } + Byte[] data = new byte[]{ this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + coilValue[1], + coilValue[0], + this.crc[0], + this.crc[1] + }; + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 8; + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length - 2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length - 2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x85 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x85 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x85 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x85 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + if ((crc[0] != data[12] | crc[1] != data[13]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + WriteSingleCoil(startingAddress, value); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + + } + else + { + countRetries++; + WriteSingleCoil(startingAddress, value); + } + } + } + } + + + /// + /// Write single Register to Master device (FC6). + /// + /// Register to be written + /// Register Value to be written + public void WriteSingleRegister(int startingAddress, int value) + { + if (debug) StoreLogData.Instance.Store("FC6 (Write single register to Master device), StartingAddress: "+ startingAddress+", Value: " + value, System.DateTime.Now); + transactionIdentifierInternal++; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + byte[] registerValue = new byte[2]; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int)0x0000); + this.length = BitConverter.GetBytes((int)0x0006); + this.functionCode = 0x06; + this.startingAddress = BitConverter.GetBytes(startingAddress); + registerValue = BitConverter.GetBytes((int)value); + + Byte[] data = new byte[]{ this.transactionIdentifier[1], + this.transactionIdentifier[0], + this.protocolIdentifier[1], + this.protocolIdentifier[0], + this.length[1], + this.length[0], + this.unitIdentifier, + this.functionCode, + this.startingAddress[1], + this.startingAddress[0], + registerValue[1], + registerValue[0], + this.crc[0], + this.crc[1] + }; + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + data[12] = crc[0]; + data[13] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 8; +// serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, 8); + if (debug) + { + byte [] debugData = new byte[8]; + Array.Copy(data, 6, debugData, 0, 8); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[8]; + Array.Copy(data, 6, sendData, 0, 8); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length - 2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length - 2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x86 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x86 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x86 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x86 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + if ((crc[0] != data[12] | crc[1] != data[13]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + WriteSingleRegister(startingAddress, value); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + + } + else + { + countRetries++; + WriteSingleRegister(startingAddress, value); + } + } + } + } + + /// + /// Write multiple coils to Master device (FC15). + /// + /// First coil to be written + /// Coil Values to be written + public void WriteMultipleCoils(int startingAddress, bool[] values) + { + string debugString = ""; + for (int i = 0; i < values.Length;i++) + debugString = debugString + values[i] + " "; + if (debug) StoreLogData.Instance.Store("FC15 (Write multiple coils to Master device), StartingAddress: "+ startingAddress+", Values: " + debugString, System.DateTime.Now); + transactionIdentifierInternal++; + byte byteCount = (byte)((values.Length % 8 != 0 ? values.Length / 8 + 1: (values.Length / 8))); + byte[] quantityOfOutputs = BitConverter.GetBytes((int)values.Length); + byte singleCoilValue = 0; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int)0x0000); + this.length = BitConverter.GetBytes((int)(7+(byteCount))); + this.functionCode = 0x0F; + this.startingAddress = BitConverter.GetBytes(startingAddress); + + + + Byte[] data = new byte[14 +2 + (values.Length % 8 != 0 ? values.Length/8 : (values.Length / 8)-1)]; + data[0] = this.transactionIdentifier[1]; + data[1] = this.transactionIdentifier[0]; + data[2] = this.protocolIdentifier[1]; + data[3] = this.protocolIdentifier[0]; + data[4] = this.length[1]; + data[5] = this.length[0]; + data[6] = this.unitIdentifier; + data[7] = this.functionCode; + data[8] = this.startingAddress[1]; + data[9] = this.startingAddress[0]; + data[10] = quantityOfOutputs[1]; + data[11] = quantityOfOutputs[0]; + data[12] = byteCount; + for (int i = 0; i < values.Length; i++) + { + if ((i % 8) == 0) + singleCoilValue = 0; + byte CoilValue; + if (values[i] == true) + CoilValue = 1; + else + CoilValue = 0; + + + singleCoilValue = (byte)((int)CoilValue<<(i%8) | (int)singleCoilValue); + + data[13 + (i / 8)] = singleCoilValue; + } + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data.Length - 8), 6)); + data[data.Length - 2] = crc[0]; + data[data.Length - 1] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 8; + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, data.Length - 6); + if (debug) + { + byte [] debugData = new byte[data.Length - 6]; + Array.Copy(data, 6, debugData, 0, data.Length - 6); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length - 6]; + Array.Copy(data, 6, sendData, 0, data.Length - 6); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x8F & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x8F & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x8F & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x8F & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + if ((crc[0] != data[12] | crc[1] != data[13]) & dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + WriteMultipleCoils(startingAddress, values); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + + } + else + { + countRetries++; + WriteMultipleCoils(startingAddress, values); + } + } + } + } + + /// + /// Write multiple registers to Master device (FC16). + /// + /// First register to be written + /// register Values to be written + public void WriteMultipleRegisters(int startingAddress, int[] values) + { + string debugString = ""; + for (int i = 0; i < values.Length;i++) + debugString = debugString + values[i] + " "; + if (debug) StoreLogData.Instance.Store("FC16 (Write multiple Registers to Server device), StartingAddress: "+ startingAddress+", Values: " + debugString, System.DateTime.Now); + transactionIdentifierInternal++; + byte byteCount = (byte)(values.Length * 2); + byte[] quantityOfOutputs = BitConverter.GetBytes((int)values.Length); + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int)0x0000); + this.length = BitConverter.GetBytes((int)(7+values.Length*2)); + this.functionCode = 0x10; + this.startingAddress = BitConverter.GetBytes(startingAddress); + + Byte[] data = new byte[13+2 + values.Length*2]; + data[0] = this.transactionIdentifier[1]; + data[1] = this.transactionIdentifier[0]; + data[2] = this.protocolIdentifier[1]; + data[3] = this.protocolIdentifier[0]; + data[4] = this.length[1]; + data[5] = this.length[0]; + data[6] = this.unitIdentifier; + data[7] = this.functionCode; + data[8] = this.startingAddress[1]; + data[9] = this.startingAddress[0]; + data[10] = quantityOfOutputs[1]; + data[11] = quantityOfOutputs[0]; + data[12] = byteCount; + for (int i = 0; i < values.Length; i++) + { + byte[] singleRegisterValue = BitConverter.GetBytes((int)values[i]); + data[13 + i*2] = singleRegisterValue[1]; + data[14 + i*2] = singleRegisterValue[0]; + } + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data.Length - 8), 6)); + data[data.Length - 2] = crc[0]; + data[data.Length - 1] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 8; +// serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, data.Length - 6); + + if (debug) + { + byte [] debugData = new byte[data.Length - 6]; + Array.Copy(data, 6, debugData, 0, data.Length - 6); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length - 6]; + Array.Copy(data, 6, sendData, 0, data.Length - 6); + SendDataChanged(this); + + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x90 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x90 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x90 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x90 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + if (serialport != null) + { + crc = BitConverter.GetBytes(calculateCRC(data, 6, 6)); + if ((crc[0] != data[12] | crc[1] != data[13]) &dataReceived) + { + if (debug) StoreLogData.Instance.Store("CRCCheckFailedException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new EasyModbus.Exceptions.CRCCheckFailedException("Response CRC check failed"); + } + else + { + countRetries++; + WriteMultipleRegisters(startingAddress, values); + } + } + else if (!dataReceived) + { + if (debug) StoreLogData.Instance.Store("TimeoutException Throwed", System.DateTime.Now); + if (NumberOfRetries <= countRetries) + { + countRetries = 0; + throw new TimeoutException("No Response from Modbus Slave"); + + } + else + { + countRetries++; + WriteMultipleRegisters(startingAddress, values); + } + } + } + } + + /// + /// Read/Write Multiple Registers (FC23). + /// + /// First input register to read + /// Number of input registers to read + /// First input register to write + /// Values to write + /// Int Array which contains the Holding registers + public int[] ReadWriteMultipleRegisters(int startingAddressRead, int quantityRead, int startingAddressWrite, int[] values) + { + + string debugString = ""; + for (int i = 0; i < values.Length;i++) + debugString = debugString + values[i] + " "; + if (debug) StoreLogData.Instance.Store("FC23 (Read and Write multiple Registers to Server device), StartingAddress Read: "+ startingAddressRead+ ", Quantity Read: "+quantityRead+", startingAddressWrite: " + startingAddressWrite +", Values: " + debugString, System.DateTime.Now); + transactionIdentifierInternal++; + byte [] startingAddressReadLocal = new byte[2]; + byte [] quantityReadLocal = new byte[2]; + byte[] startingAddressWriteLocal = new byte[2]; + byte[] quantityWriteLocal = new byte[2]; + byte writeByteCountLocal = 0; + if (serialport != null) + if (!serialport.IsOpen) + { + if (debug) StoreLogData.Instance.Store("SerialPortNotOpenedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened"); + } + if (tcpClient == null & !udpFlag & serialport == null) + { + if (debug) StoreLogData.Instance.Store("ConnectionException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ConnectionException("connection error"); + } + if (startingAddressRead > 65535 | quantityRead > 125 | startingAddressWrite > 65535 | values.Length > 121) + { + if (debug) StoreLogData.Instance.Store("ArgumentException Throwed", System.DateTime.Now); + throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 2000"); + } + int[] response; + this.transactionIdentifier = BitConverter.GetBytes((uint)transactionIdentifierInternal); + this.protocolIdentifier = BitConverter.GetBytes((int)0x0000); + this.length = BitConverter.GetBytes((int)11 + values.Length * 2); + this.functionCode = 0x17; + startingAddressReadLocal = BitConverter.GetBytes(startingAddressRead); + quantityReadLocal = BitConverter.GetBytes(quantityRead); + startingAddressWriteLocal = BitConverter.GetBytes(startingAddressWrite); + quantityWriteLocal = BitConverter.GetBytes(values.Length); + writeByteCountLocal = Convert.ToByte(values.Length * 2); + Byte[] data = new byte[17 +2+ values.Length*2]; + data[0] = this.transactionIdentifier[1]; + data[1] = this.transactionIdentifier[0]; + data[2] = this.protocolIdentifier[1]; + data[3] = this.protocolIdentifier[0]; + data[4] = this.length[1]; + data[5] = this.length[0]; + data[6] = this.unitIdentifier; + data[7] = this.functionCode; + data[8] = startingAddressReadLocal[1]; + data[9] = startingAddressReadLocal[0]; + data[10] = quantityReadLocal[1]; + data[11] = quantityReadLocal[0]; + data[12] = startingAddressWriteLocal[1]; + data[13] = startingAddressWriteLocal[0]; + data[14] = quantityWriteLocal[1]; + data[15] = quantityWriteLocal[0]; + data[16] = writeByteCountLocal; + + for (int i = 0; i < values.Length; i++) + { + byte[] singleRegisterValue = BitConverter.GetBytes((int)values[i]); + data[17 + i*2] = singleRegisterValue[1]; + data[18 + i*2] = singleRegisterValue[0]; + } + crc = BitConverter.GetBytes(calculateCRC(data, (ushort)(data.Length - 8), 6)); + data[data.Length - 2] = crc[0]; + data[data.Length - 1] = crc[1]; + if (serialport != null) + { + dataReceived = false; + bytesToRead = 5 + 2*quantityRead; + // serialport.ReceivedBytesThreshold = bytesToRead; + serialport.Write(data, 6, data.Length - 6); + if (debug) + { + byte [] debugData = new byte[data.Length - 6]; + Array.Copy(data, 6, debugData, 0, data.Length - 6); + if (debug) StoreLogData.Instance.Store("Send Serial-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length - 6]; + Array.Copy(data, 6, sendData, 0, data.Length - 6); + SendDataChanged(this); + } + data = new byte[2100]; + readBuffer = new byte[256]; + DateTime dateTimeSend = DateTime.Now; + byte receivedUnitIdentifier = 0xFF; + while (receivedUnitIdentifier != this.unitIdentifier & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + { + while (dataReceived == false & !((DateTime.Now.Ticks - dateTimeSend.Ticks) > TimeSpan.TicksPerMillisecond * this.connectTimeout)) + System.Threading.Thread.Sleep(1); + data = new byte[2100]; + Array.Copy(readBuffer, 0, data, 6, readBuffer.Length); + receivedUnitIdentifier = data[6]; + } + if (receivedUnitIdentifier != this.unitIdentifier) + data = new byte[2100]; + else + countRetries = 0; + } + else if (tcpClient.Client.Connected | udpFlag) + { + if (udpFlag) + { + UdpClient udpClient = new UdpClient(); + IPEndPoint endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), port); + udpClient.Send(data, data.Length-2, endPoint); + portOut = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + udpClient.Client.ReceiveTimeout = 5000; + endPoint = new IPEndPoint(System.Net.IPAddress.Parse(ipAddress), portOut); + data = udpClient.Receive(ref endPoint); + } + else + { + stream.Write(data, 0, data.Length-2); + if (debug) + { + byte [] debugData = new byte[data.Length-2]; + Array.Copy(data, 0, debugData, 0, data.Length-2); + if (debug) StoreLogData.Instance.Store("Send ModbusTCP-Data: "+BitConverter.ToString(debugData) ,System.DateTime.Now); + } + if (SendDataChanged != null) + { + sendData = new byte[data.Length-2]; + Array.Copy(data, 0, sendData, 0, data.Length-2); + SendDataChanged(this); + + } + data = new Byte[2100]; + int NumberOfBytes = stream.Read(data, 0, data.Length); + if (ReceiveDataChanged != null) + { + receiveData = new byte[NumberOfBytes]; + Array.Copy(data, 0, receiveData, 0, NumberOfBytes); + if (debug) StoreLogData.Instance.Store("Receive ModbusTCP-Data: " + BitConverter.ToString(receiveData), System.DateTime.Now); + ReceiveDataChanged(this); + } + } + } + if (data[7] == 0x97 & data[8] == 0x01) + { + if (debug) StoreLogData.Instance.Store("FunctionCodeNotSupportedException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.FunctionCodeNotSupportedException("Function code not supported by master"); + } + if (data[7] == 0x97 & data[8] == 0x02) + { + if (debug) StoreLogData.Instance.Store("StartingAddressInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.StartingAddressInvalidException("Starting address invalid or starting address + quantity invalid"); + } + if (data[7] == 0x97 & data[8] == 0x03) + { + if (debug) StoreLogData.Instance.Store("QuantityInvalidException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.QuantityInvalidException("quantity invalid"); + } + if (data[7] == 0x97 & data[8] == 0x04) + { + if (debug) StoreLogData.Instance.Store("ModbusException Throwed", System.DateTime.Now); + throw new EasyModbus.Exceptions.ModbusException("error reading"); + } + response = new int[quantityRead]; + for (int i = 0; i < quantityRead; i++) + { + byte lowByte; + byte highByte; + highByte = data[9 + i * 2]; + lowByte = data[9 + i * 2 + 1]; + + data[9 + i * 2] = lowByte; + data[9 + i * 2 + 1] = highByte; + + response[i] = BitConverter.ToInt16(data, (9 + i * 2)); + } + return (response); + } + + /// + /// Close connection to Master Device. + /// + public void Disconnect() + { + if (debug) StoreLogData.Instance.Store("Disconnect", System.DateTime.Now); + if (serialport != null) + { + if (serialport.IsOpen & !this.receiveActive) + serialport.Close(); + if (ConnectedChanged != null) + ConnectedChanged(this); + return; + } + if (stream != null) + stream.Close(); + if (tcpClient != null) + tcpClient.Close(); + connected = false; + if (ConnectedChanged != null) + ConnectedChanged(this); + + } + + /// + /// Destructor - Close connection to Master Device. + /// + ~ ModbusClient() + { + if (debug) StoreLogData.Instance.Store("Destructor called - automatically disconnect", System.DateTime.Now); + if (serialport != null) + { + if (serialport.IsOpen) + serialport.Close(); + return; + } + if (tcpClient != null & !udpFlag) + { + if (stream !=null) + stream.Close(); + tcpClient.Close(); + } + } + + /// + /// Returns "TRUE" if Client is connected to Server and "FALSE" if not. In case of Modbus RTU returns if COM-Port is opened + /// + public bool Connected + { + get + { + if (serialport != null) + { + return (serialport.IsOpen); + } + + if (udpFlag & tcpClient != null) + return true; + if (tcpClient == null) + return false; + else + { + return connected; + + } + + } + } + + public bool Available(int timeout) + { + // Ping's the local machine. + System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping(); + IPAddress address = System.Net.IPAddress.Parse(ipAddress); + + // Create a buffer of 32 bytes of data to be transmitted. + string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + byte[] buffer = System.Text.Encoding.ASCII.GetBytes(data); + + // Wait 10 seconds for a reply. + System.Net.NetworkInformation.PingReply reply = pingSender.Send(address, timeout, buffer); + + if (reply.Status == System.Net.NetworkInformation.IPStatus.Success) + return true; + else + return false; + } + + /// + /// Gets or Sets the IP-Address of the Server. + /// + public string IPAddress + { + get + { + return ipAddress; + } + set + { + ipAddress = value; + } + } + + /// + /// Gets or Sets the Port were the Modbus-TCP Server is reachable (Standard is 502). + /// + public int Port + { + get + { + return port; + } + set + { + port = value; + } + } + + /// + /// Gets or Sets the UDP-Flag to activate Modbus UDP. + /// + public bool UDPFlag + { + get + { + return udpFlag; + } + set + { + udpFlag = value; + } + } + + /// + /// Gets or Sets the Unit identifier in case of serial connection (Default = 0) + /// + public byte UnitIdentifier + { + get + { + return unitIdentifier; + } + set + { + unitIdentifier = value; + } + } + + + /// + /// Gets or Sets the Baudrate for serial connection (Default = 9600) + /// + public int Baudrate + { + get + { + return baudRate; + } + set + { + baudRate = value; + } + } + + /// + /// Gets or Sets the of Parity in case of serial connection + /// + public Parity Parity + { + get + { + if (serialport != null) + return parity; + else + return Parity.Even; + } + set + { + if (serialport != null) + parity = value; + } + } + + + /// + /// Gets or Sets the number of stopbits in case of serial connection + /// + public StopBits StopBits + { + get + { + if (serialport != null) + return stopBits; + else + return StopBits.One; + } + set + { + if (serialport != null) + stopBits = value; + } + } + + /// + /// Gets or Sets the connection Timeout in case of ModbusTCP connection + /// + public int ConnectionTimeout + { + get + { + return connectTimeout; + } + set + { + connectTimeout = value; + } + } + + /// + /// Gets or Sets the serial Port + /// + public string SerialPort + { + get + { + + return serialport.PortName; + } + set + { + if (value == null) + { + serialport = null; + return; + } + if (serialport != null) + serialport.Close(); + this.serialport = new SerialPort(); + this.serialport.PortName = value; + serialport.BaudRate = baudRate; + serialport.Parity = parity; + serialport.StopBits = stopBits; + serialport.WriteTimeout = 10000; + serialport.ReadTimeout = connectTimeout; + serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + } + } + + /// + /// Gets or Sets the Filename for the LogFile + /// + public string LogFileFilename + { + get + { + return StoreLogData.Instance.Filename; + } + set + { + StoreLogData.Instance.Filename = value; + if (StoreLogData.Instance.Filename != null) + debug = true; + else + debug = false; + } + } + + } +} diff --git a/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Helpers.cs b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Helpers.cs new file mode 100644 index 0000000..ebe9409 --- /dev/null +++ b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Helpers.cs @@ -0,0 +1,506 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EasyModbus +{ + public partial class ModbusClient + { + + public enum RegisterOrder { LowHigh = 0, HighLow = 1 }; + + /// + /// Calculates the CRC16 for Modbus-RTU + /// + /// Byte buffer to send + /// Number of bytes to calculate CRC + /// First byte in buffer to start calculating CRC + internal static UInt16 calculateCRC(byte[] data, UInt16 numberOfBytes, int startByte) + { + byte[] auchCRCHi = { + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, + 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, + 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, + 0x40 + }; + + byte[] auchCRCLo = { + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, + 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, + 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, + 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, + 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, + 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, + 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, + 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, + 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, + 0x40 + }; + UInt16 usDataLen = numberOfBytes; + byte uchCRCHi = 0xFF; + byte uchCRCLo = 0xFF; + int i = 0; + int uIndex; + while (usDataLen > 0) + { + usDataLen--; + if ((i + startByte) < data.Length) + { + uIndex = uchCRCLo ^ data[i + startByte]; + uchCRCLo = (byte)(uchCRCHi ^ auchCRCHi[uIndex]); + uchCRCHi = auchCRCLo[uIndex]; + } + i++; + } + return (UInt16)((UInt16)uchCRCHi << 8 | uchCRCLo); + } + + /// + /// Converts two ModbusRegisters to Float - Example: EasyModbus.ModbusClient.ConvertRegistersToFloat(modbusClient.ReadHoldingRegisters(19,2)) + /// + /// Two Register values received from Modbus + /// Connected float value + public static float ConvertRegistersToFloat(int[] registers) + { + if (registers.Length != 2) + throw new ArgumentException("Input Array length invalid - Array langth must be '2'"); + int highRegister = registers[1]; + int lowRegister = registers[0]; + byte[] highRegisterBytes = BitConverter.GetBytes(highRegister); + byte[] lowRegisterBytes = BitConverter.GetBytes(lowRegister); + byte[] floatBytes = { + lowRegisterBytes[0], + lowRegisterBytes[1], + highRegisterBytes[0], + highRegisterBytes[1] + }; + return BitConverter.ToSingle(floatBytes, 0); + } + + + /// + /// Converts two ModbusRegisters to Float, Registers can by swapped + /// + /// Two Register values received from Modbus + /// Desired Word Order (Low Register first or High Register first + /// Connected float value + public static float ConvertRegistersToFloat(int[] registers, RegisterOrder registerOrder) + { + int[] swappedRegisters = { registers[0], registers[1] }; + if (registerOrder == RegisterOrder.HighLow) + swappedRegisters = new int[] { registers[1], registers[0] }; + return ConvertRegistersToFloat(swappedRegisters); + } + + /// + /// Converts two ModbusRegisters to 32 Bit Integer value + /// + /// Two Register values received from Modbus + /// Connected 32 Bit Integer value + public static Int32 ConvertRegistersToInt(int[] registers) + { + if (registers.Length != 2) + throw new ArgumentException("Input Array length invalid - Array langth must be '2'"); + int highRegister = registers[1]; + int lowRegister = registers[0]; + byte[] highRegisterBytes = BitConverter.GetBytes(highRegister); + byte[] lowRegisterBytes = BitConverter.GetBytes(lowRegister); + byte[] doubleBytes = { + lowRegisterBytes[0], + lowRegisterBytes[1], + highRegisterBytes[0], + highRegisterBytes[1] + }; + return BitConverter.ToInt32(doubleBytes, 0); + } + + /// + /// Converts two ModbusRegisters to 32 Bit Integer Value - Registers can be swapped + /// + /// Two Register values received from Modbus + /// Desired Word Order (Low Register first or High Register first + /// Connecteds 32 Bit Integer value + public static Int32 ConvertRegistersToInt(int[] registers, RegisterOrder registerOrder) + { + int[] swappedRegisters = { registers[0], registers[1] }; + if (registerOrder == RegisterOrder.HighLow) + swappedRegisters = new int[] { registers[1], registers[0] }; + return ConvertRegistersToInt(swappedRegisters); + } + + /// + /// Convert four 16 Bit Registers to 64 Bit Integer value Register Order "LowHigh": Reg0: Low Word.....Reg3: High Word, "HighLow": Reg0: High Word.....Reg3: Low Word + /// + /// four Register values received from Modbus + /// 64 bit value + + public static Int64 ConvertRegistersToLong(int[] registers) + { + if (registers.Length != 4) + throw new ArgumentException("Input Array length invalid - Array langth must be '4'"); + int highRegister = registers[3]; + int highLowRegister = registers[2]; + int lowHighRegister = registers[1]; + int lowRegister = registers[0]; + byte[] highRegisterBytes = BitConverter.GetBytes(highRegister); + byte[] highLowRegisterBytes = BitConverter.GetBytes(highLowRegister); + byte[] lowHighRegisterBytes = BitConverter.GetBytes(lowHighRegister); + byte[] lowRegisterBytes = BitConverter.GetBytes(lowRegister); + byte[] longBytes = { + lowRegisterBytes[0], + lowRegisterBytes[1], + lowHighRegisterBytes[0], + lowHighRegisterBytes[1], + highLowRegisterBytes[0], + highLowRegisterBytes[1], + highRegisterBytes[0], + highRegisterBytes[1] + }; + return BitConverter.ToInt64(longBytes, 0); + } + + /// + /// Convert four 16 Bit Registers to 64 Bit Integer value - Registers can be swapped + /// + /// four Register values received from Modbus + /// Desired Word Order (Low Register first or High Register first + /// Connected 64 Bit Integer value + public static Int64 ConvertRegistersToLong(int[] registers, RegisterOrder registerOrder) + { + if (registers.Length != 4) + throw new ArgumentException("Input Array length invalid - Array langth must be '4'"); + int[] swappedRegisters = { registers[0], registers[1], registers[2], registers[3] }; + if (registerOrder == RegisterOrder.HighLow) + swappedRegisters = new int[] { registers[3], registers[2], registers[1], registers[0] }; + return ConvertRegistersToLong(swappedRegisters); + } + + /// + /// Convert four 16 Bit Registers to 64 Bit double prec. value Register Order "LowHigh": Reg0: Low Word.....Reg3: High Word, "HighLow": Reg0: High Word.....Reg3: Low Word + /// + /// four Register values received from Modbus + /// 64 bit value + public static double ConvertRegistersToDouble(int[] registers) + { + if (registers.Length != 4) + throw new ArgumentException("Input Array length invalid - Array langth must be '4'"); + int highRegister = registers[3]; + int highLowRegister = registers[2]; + int lowHighRegister = registers[1]; + int lowRegister = registers[0]; + byte[] highRegisterBytes = BitConverter.GetBytes(highRegister); + byte[] highLowRegisterBytes = BitConverter.GetBytes(highLowRegister); + byte[] lowHighRegisterBytes = BitConverter.GetBytes(lowHighRegister); + byte[] lowRegisterBytes = BitConverter.GetBytes(lowRegister); + byte[] longBytes = { + lowRegisterBytes[0], + lowRegisterBytes[1], + lowHighRegisterBytes[0], + lowHighRegisterBytes[1], + highLowRegisterBytes[0], + highLowRegisterBytes[1], + highRegisterBytes[0], + highRegisterBytes[1] + }; + return BitConverter.ToDouble(longBytes, 0); + } + + /// + /// Convert four 16 Bit Registers to 64 Bit double prec. value - Registers can be swapped + /// + /// four Register values received from Modbus + /// Desired Word Order (Low Register first or High Register first + /// Connected double prec. float value + public static double ConvertRegistersToDouble(int[] registers, RegisterOrder registerOrder) + { + if (registers.Length != 4) + throw new ArgumentException("Input Array length invalid - Array langth must be '4'"); + int[] swappedRegisters = { registers[0], registers[1], registers[2], registers[3] }; + if (registerOrder == RegisterOrder.HighLow) + swappedRegisters = new int[] { registers[3], registers[2], registers[1], registers[0] }; + return ConvertRegistersToDouble(swappedRegisters); + } + + /// + /// Converts float to two ModbusRegisters - Example: modbusClient.WriteMultipleRegisters(24, EasyModbus.ModbusClient.ConvertFloatToTwoRegisters((float)1.22)); + /// + /// Float value which has to be converted into two registers + /// Register values + public static int[] ConvertFloatToRegisters(float floatValue) + { + byte[] floatBytes = BitConverter.GetBytes(floatValue); + byte[] highRegisterBytes = + { + floatBytes[2], + floatBytes[3], + 0, + 0 + }; + byte[] lowRegisterBytes = + { + + floatBytes[0], + floatBytes[1], + 0, + 0 + }; + int[] returnValue = + { + BitConverter.ToInt32(lowRegisterBytes,0), + BitConverter.ToInt32(highRegisterBytes,0) + }; + return returnValue; + } + + /// + /// Converts float to two ModbusRegisters Registers - Registers can be swapped + /// + /// Float value which has to be converted into two registers + /// Desired Word Order (Low Register first or High Register first + /// Register values + public static int[] ConvertFloatToRegisters(float floatValue, RegisterOrder registerOrder) + { + int[] registerValues = ConvertFloatToRegisters(floatValue); + int[] returnValue = registerValues; + if (registerOrder == RegisterOrder.HighLow) + returnValue = new Int32[] { registerValues[1], registerValues[0] }; + return returnValue; + } + + /// + /// Converts 32 Bit Value to two ModbusRegisters + /// + /// Int value which has to be converted into two registers + /// Register values + public static int[] ConvertIntToRegisters(Int32 intValue) + { + byte[] doubleBytes = BitConverter.GetBytes(intValue); + byte[] highRegisterBytes = + { + doubleBytes[2], + doubleBytes[3], + 0, + 0 + }; + byte[] lowRegisterBytes = + { + + doubleBytes[0], + doubleBytes[1], + 0, + 0 + }; + int[] returnValue = + { + BitConverter.ToInt32(lowRegisterBytes,0), + BitConverter.ToInt32(highRegisterBytes,0) + }; + return returnValue; + } + + /// + /// Converts 32 Bit Value to two ModbusRegisters Registers - Registers can be swapped + /// + /// Double value which has to be converted into two registers + /// Desired Word Order (Low Register first or High Register first + /// Register values + public static int[] ConvertIntToRegisters(Int32 intValue, RegisterOrder registerOrder) + { + int[] registerValues = ConvertIntToRegisters(intValue); + int[] returnValue = registerValues; + if (registerOrder == RegisterOrder.HighLow) + returnValue = new Int32[] { registerValues[1], registerValues[0] }; + return returnValue; + } + + /// + /// Converts 64 Bit Value to four ModbusRegisters + /// + /// long value which has to be converted into four registers + /// Register values + public static int[] ConvertLongToRegisters(Int64 longValue) + { + byte[] longBytes = BitConverter.GetBytes(longValue); + byte[] highRegisterBytes = + { + longBytes[6], + longBytes[7], + 0, + 0 + }; + byte[] highLowRegisterBytes = + { + longBytes[4], + longBytes[5], + 0, + 0 + }; + byte[] lowHighRegisterBytes = + { + longBytes[2], + longBytes[3], + 0, + 0 + }; + byte[] lowRegisterBytes = + { + + longBytes[0], + longBytes[1], + 0, + 0 + }; + int[] returnValue = + { + BitConverter.ToInt32(lowRegisterBytes,0), + BitConverter.ToInt32(lowHighRegisterBytes,0), + BitConverter.ToInt32(highLowRegisterBytes,0), + BitConverter.ToInt32(highRegisterBytes,0) + }; + return returnValue; + } + + /// + /// Converts 64 Bit Value to four ModbusRegisters - Registers can be swapped + /// + /// long value which has to be converted into four registers + /// Desired Word Order (Low Register first or High Register first + /// Register values + public static int[] ConvertLongToRegisters(Int64 longValue, RegisterOrder registerOrder) + { + int[] registerValues = ConvertLongToRegisters(longValue); + int[] returnValue = registerValues; + if (registerOrder == RegisterOrder.HighLow) + returnValue = new int[] { registerValues[3], registerValues[2], registerValues[1], registerValues[0] }; + return returnValue; + } + + /// + /// Converts 64 Bit double prec Value to four ModbusRegisters + /// + /// double value which has to be converted into four registers + /// Register values + public static int[] ConvertDoubleToRegisters(double doubleValue) + { + byte[] doubleBytes = BitConverter.GetBytes(doubleValue); + byte[] highRegisterBytes = + { + doubleBytes[6], + doubleBytes[7], + 0, + 0 + }; + byte[] highLowRegisterBytes = + { + doubleBytes[4], + doubleBytes[5], + 0, + 0 + }; + byte[] lowHighRegisterBytes = + { + doubleBytes[2], + doubleBytes[3], + 0, + 0 + }; + byte[] lowRegisterBytes = + { + + doubleBytes[0], + doubleBytes[1], + 0, + 0 + }; + int[] returnValue = + { + BitConverter.ToInt32(lowRegisterBytes,0), + BitConverter.ToInt32(lowHighRegisterBytes,0), + BitConverter.ToInt32(highLowRegisterBytes,0), + BitConverter.ToInt32(highRegisterBytes,0) + }; + return returnValue; + } + + /// + /// Converts 64 Bit double prec. Value to four ModbusRegisters - Registers can be swapped + /// + /// double value which has to be converted into four registers + /// Desired Word Order (Low Register first or High Register first + /// Register values + public static int[] ConvertDoubleToRegisters(double doubleValue, RegisterOrder registerOrder) + { + int[] registerValues = ConvertDoubleToRegisters(doubleValue); + int[] returnValue = registerValues; + if (registerOrder == RegisterOrder.HighLow) + returnValue = new int[] { registerValues[3], registerValues[2], registerValues[1], registerValues[0] }; + return returnValue; + } + + /// + /// Converts 16 - Bit Register values to String + /// + /// Register array received via Modbus + /// First Register containing the String to convert + /// number of characters in String (must be even) + /// Converted String + public static string ConvertRegistersToString(int[] registers, int offset, int stringLength) + { + byte[] result = new byte[stringLength]; + byte[] registerResult = new byte[2]; + + for (int i = 0; i < stringLength / 2; i++) + { + registerResult = BitConverter.GetBytes(registers[offset + i]); + result[i * 2] = registerResult[0]; + result[i * 2 + 1] = registerResult[1]; + } + return System.Text.Encoding.Default.GetString(result); + } + + /// + /// Converts a String to 16 - Bit Registers + /// + /// Register array received via Modbus + /// Converted String + public static int[] ConvertStringToRegisters(string stringToConvert) + { + byte[] array = System.Text.Encoding.ASCII.GetBytes(stringToConvert); + int[] returnarray = new int[stringToConvert.Length / 2 + stringToConvert.Length % 2]; + for (int i = 0; i < returnarray.Length; i++) + { + returnarray[i] = array[i * 2]; + if (i * 2 + 1 < array.Length) + { + returnarray[i] = returnarray[i] | ((int)array[i * 2 + 1] << 8); + } + } + return returnarray; + } + + } +} diff --git a/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Protocol.cs b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Protocol.cs new file mode 100644 index 0000000..161ffba --- /dev/null +++ b/EasyModbus_Standard2.1/ModbusClient/EasyModbus.ModbusClient.Protocol.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EasyModbus +{ + + + + /// + /// Protocol Data Unit (PDU) - As Specified in the Modbus Appliction Protocol specification V1.1b3 Page 3 + /// The PDU consists of: + /// Function code - 1 byte + /// Data - x bytes + /// The "Data" section is described in the Documentation of the Function code and will be created according to the given Function code + /// + class ProtocolDataUnit + { + public byte FunctionCode { get; set; } + private byte[] data; + public ushort StartingAddressRead { get; set; } + public ushort StartingAddressWrite { get; set; } + public ushort QuantityRead { get; set; } + public ushort QuantityWrite { get; set; } + public byte ByteCount { get; } + public byte ErroCode { get; } + public byte ExceptionCode { get; } + public int[] RegisterDataInt { get; set; } + + public bool[] RegisterDataBool { get; set; } + + + + public byte[] Data + { + //return the data in case of a request + get + { + Byte[] returnvalue = null; + switch (FunctionCode) + { + + // FC01 (0x01) "Read Coils" Page 11 + case 1: + returnvalue = new byte[] + { + BitConverter.GetBytes((ushort)StartingAddressRead)[1], + BitConverter.GetBytes((ushort)StartingAddressRead)[0], + BitConverter.GetBytes((ushort)QuantityRead)[1], + BitConverter.GetBytes((ushort)QuantityRead)[0], + + }; + break; + // FC02 (0x02) "Read Discrete Inputs" Page 12 + case 2: + returnvalue = new byte[] + { + BitConverter.GetBytes((ushort)StartingAddressRead)[1], + BitConverter.GetBytes((ushort)StartingAddressRead)[0], + BitConverter.GetBytes((ushort)QuantityRead)[1], + BitConverter.GetBytes((ushort)QuantityRead)[0], + + }; + break; + } + return returnvalue; + } + //set the data in case of a response + set + { + switch (FunctionCode) + { + // FC 01: Read Coils and 02 Read Discrete Inputs provide the same response + case 1: case 2: + byte byteCount = value[1]; + RegisterDataBool = new bool[QuantityRead]; + for (int i = 0; i < QuantityRead; i++) + { + int intData = data[i / 8]; + int mask = Convert.ToInt32(Math.Pow(2, (i % 8))); + RegisterDataBool[i] = (Convert.ToBoolean((intData & mask) / mask)); + } + break; + + } + } + + + } + + } + + /// + /// Application Data Unit (ADU) - As Specified in the Modbus Appliction Protocol specification V1.1b3 Page 3 (or Modbus Messaging on TCP/IP Implementation Guide Page 4) + /// The ADU consists of: + /// + /// MBAP Header (only for Modbus TCP) + /// Transaction Identifier - 2 Bytes + /// Protocol Identiifier - 2 Bytes + /// Length - 2 Bytes + /// + /// Additional Address - 1 byte + /// PDU - x Byte + /// CRC - 2 byte (not used for Modbus TCP) + /// The "Data" section is described in the Documentation of the Function code and will be created according to the given Function code + /// + class ApplicationDataUnit : ProtocolDataUnit + { + + public ushort TransactionIdentifier { get; set; } + private ushort protocolIdentifier = 0; + + public byte UnitIdentifier { get; set; } + /// + /// Constructor, the Function code has to be handed over at instantiation + /// + /// + public ApplicationDataUnit(byte functionCode) + { + this.FunctionCode = functionCode; + } + + public byte[] Mbap_Header + { + get + { + ushort length = 0x0006; + if (FunctionCode == 15) + { + byte byteCount = (byte)((RegisterDataBool.Length % 8 != 0 ? RegisterDataBool.Length / 8 + 1 : (RegisterDataBool.Length / 8))); + length = (ushort)(7 + byteCount); + } + if (FunctionCode == 16) + length = (ushort)(7 + RegisterDataInt.Length * 2); + if (FunctionCode == 23) + length = (ushort)(11 + RegisterDataInt.Length * 2); + + Byte[] returnvalue = new byte[] + { + BitConverter.GetBytes((ushort)TransactionIdentifier)[1], + BitConverter.GetBytes((ushort)TransactionIdentifier)[0], + BitConverter.GetBytes((ushort)protocolIdentifier)[1], + BitConverter.GetBytes((ushort)protocolIdentifier)[0], + BitConverter.GetBytes((ushort)length)[1], + BitConverter.GetBytes((ushort)length)[0], + UnitIdentifier + }; + + return returnvalue; + } + } + + + + public byte[] Payload { + // Return the Payload in case of a request + get + { + List returnvalue = new List(); + + returnvalue.AddRange(this.Mbap_Header); + returnvalue.Add(FunctionCode); + returnvalue.AddRange(Data); + + byte [] crc = BitConverter.GetBytes(ModbusClient.calculateCRC(returnvalue.ToArray(), (ushort)(returnvalue.Count - 8), 6)); + returnvalue.AddRange(crc); + return returnvalue.ToArray(); + } + // Set the Payload in case of a resonse + set + { + + TransactionIdentifier = BitConverter.ToUInt16(value, 0); + UnitIdentifier = value[6]; + + } + + + } + + + } + + + + + }