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];
+
+ }
+
+
+ }
+
+
+ }
+
+
+
+
+ }