2277 lines
91 KiB
C#
2277 lines
91 KiB
C#
/*
|
|
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;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
using System.Threading;
|
|
using System.Net.NetworkInformation;
|
|
using System.IO.Ports;
|
|
|
|
namespace EasyModbus
|
|
{
|
|
#region class ModbusProtocol
|
|
/// <summary>
|
|
/// Modbus Protocol informations.
|
|
/// </summary>
|
|
public class ModbusProtocol
|
|
{
|
|
public enum ProtocolType { ModbusTCP = 0, ModbusUDP = 1, ModbusRTU = 2 };
|
|
public DateTime timeStamp;
|
|
public bool request;
|
|
public bool response;
|
|
public UInt16 transactionIdentifier;
|
|
public UInt16 protocolIdentifier;
|
|
public UInt16 length;
|
|
public byte unitIdentifier;
|
|
public byte functionCode;
|
|
public UInt16 startingAdress;
|
|
public UInt16 startingAddressRead;
|
|
public UInt16 startingAddressWrite;
|
|
public UInt16 quantity;
|
|
public UInt16 quantityRead;
|
|
public UInt16 quantityWrite;
|
|
public byte byteCount;
|
|
public byte exceptionCode;
|
|
public byte errorCode;
|
|
public UInt16[] receiveCoilValues;
|
|
public UInt16[] receiveRegisterValues;
|
|
public Int16[] sendRegisterValues;
|
|
public bool[] sendCoilValues;
|
|
public UInt16 crc;
|
|
}
|
|
#endregion
|
|
|
|
#region structs
|
|
struct NetworkConnectionParameter
|
|
{
|
|
public NetworkStream stream; //For TCP-Connection only
|
|
public Byte[] bytes;
|
|
public int portIn; //For UDP-Connection only
|
|
public IPAddress ipAddressIn; //For UDP-Connection only
|
|
}
|
|
#endregion
|
|
|
|
#region TCPHandler class
|
|
internal class TCPHandler
|
|
{
|
|
public delegate void DataChanged(object networkConnectionParameter);
|
|
public event DataChanged dataChanged;
|
|
|
|
public delegate void NumberOfClientsChanged();
|
|
public event NumberOfClientsChanged numberOfClientsChanged;
|
|
|
|
TcpListener server = null;
|
|
|
|
|
|
private List<Client> tcpClientLastRequestList = new List<Client>();
|
|
|
|
public int NumberOfConnectedClients { get; set; }
|
|
|
|
public string ipAddress = null;
|
|
|
|
/// When making a server TCP listen socket, will listen to this IP address.
|
|
public IPAddress LocalIPAddress
|
|
{
|
|
get { return localIPAddress; }
|
|
}
|
|
private IPAddress localIPAddress = IPAddress.Any;
|
|
|
|
/// <summary>
|
|
/// Listen to all network interfaces.
|
|
/// </summary>
|
|
/// <param name="port">TCP port to listen</param>
|
|
public TCPHandler(int port)
|
|
{
|
|
server = new TcpListener(LocalIPAddress, port);
|
|
server.Start();
|
|
server.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Listen to a specific network interface.
|
|
/// </summary>
|
|
/// <param name="localIPAddress">IP address of network interface to listen</param>
|
|
/// <param name="port">TCP port to listen</param>
|
|
public TCPHandler(IPAddress localIPAddress, int port)
|
|
{
|
|
this.localIPAddress = localIPAddress;
|
|
server = new TcpListener(LocalIPAddress, port);
|
|
server.Start();
|
|
server.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
|
|
}
|
|
|
|
|
|
private void AcceptTcpClientCallback(IAsyncResult asyncResult)
|
|
{
|
|
TcpClient tcpClient = new TcpClient();
|
|
try
|
|
{
|
|
tcpClient = server.EndAcceptTcpClient(asyncResult);
|
|
tcpClient.ReceiveTimeout = 4000;
|
|
if (ipAddress != null)
|
|
{
|
|
string ipEndpoint = tcpClient.Client.RemoteEndPoint.ToString();
|
|
ipEndpoint = ipEndpoint.Split(':')[0];
|
|
if (ipEndpoint != ipAddress)
|
|
{
|
|
tcpClient.Client.Disconnect(false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
try
|
|
{
|
|
server.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
|
|
Client client = new Client(tcpClient);
|
|
NetworkStream networkStream = client.NetworkStream;
|
|
networkStream.ReadTimeout = 4000;
|
|
networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client);
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
|
|
private int GetAndCleanNumberOfConnectedClients(Client client)
|
|
{
|
|
lock (this)
|
|
{
|
|
int i = 0;
|
|
bool objetExists = false;
|
|
foreach (Client clientLoop in tcpClientLastRequestList)
|
|
{
|
|
if (client.Equals(clientLoop))
|
|
objetExists = true;
|
|
}
|
|
try
|
|
{
|
|
tcpClientLastRequestList.RemoveAll(delegate (Client c)
|
|
{
|
|
return ((DateTime.Now.Ticks - c.Ticks) > 40000000);
|
|
}
|
|
|
|
);
|
|
}
|
|
catch (Exception) { }
|
|
if (!objetExists)
|
|
tcpClientLastRequestList.Add(client);
|
|
|
|
|
|
return tcpClientLastRequestList.Count;
|
|
}
|
|
}
|
|
|
|
private void ReadCallback(IAsyncResult asyncResult)
|
|
{
|
|
NetworkConnectionParameter networkConnectionParameter = new NetworkConnectionParameter();
|
|
Client client = asyncResult.AsyncState as Client;
|
|
client.Ticks = DateTime.Now.Ticks;
|
|
NumberOfConnectedClients = GetAndCleanNumberOfConnectedClients(client);
|
|
if (numberOfClientsChanged != null)
|
|
numberOfClientsChanged();
|
|
if (client != null)
|
|
{
|
|
int read;
|
|
NetworkStream networkStream = null;
|
|
try
|
|
{
|
|
networkStream = client.NetworkStream;
|
|
|
|
read = networkStream.EndRead(asyncResult);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if (read == 0)
|
|
{
|
|
//OnClientDisconnected(client.TcpClient);
|
|
//connectedClients.Remove(client);
|
|
return;
|
|
}
|
|
byte[] data = new byte[read];
|
|
Buffer.BlockCopy(client.Buffer, 0, data, 0, read);
|
|
networkConnectionParameter.bytes = data;
|
|
networkConnectionParameter.stream = networkStream;
|
|
if (dataChanged != null)
|
|
dataChanged(networkConnectionParameter);
|
|
try
|
|
{
|
|
networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Disconnect()
|
|
{
|
|
try
|
|
{
|
|
foreach (Client clientLoop in tcpClientLastRequestList)
|
|
{
|
|
clientLoop.NetworkStream.Close(00);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
server.Stop();
|
|
|
|
}
|
|
|
|
|
|
internal class Client
|
|
{
|
|
private readonly TcpClient tcpClient;
|
|
private readonly byte[] buffer;
|
|
public long Ticks { get; set; }
|
|
|
|
public Client(TcpClient tcpClient)
|
|
{
|
|
this.tcpClient = tcpClient;
|
|
int bufferSize = tcpClient.ReceiveBufferSize;
|
|
buffer = new byte[bufferSize];
|
|
}
|
|
|
|
public TcpClient TcpClient
|
|
{
|
|
get { return tcpClient; }
|
|
}
|
|
|
|
public byte[] Buffer
|
|
{
|
|
get { return buffer; }
|
|
}
|
|
|
|
public NetworkStream NetworkStream
|
|
{
|
|
get
|
|
{
|
|
|
|
return tcpClient.GetStream();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Modbus TCP Server.
|
|
/// </summary>
|
|
public class ModbusServer : IDisposable
|
|
{
|
|
private bool debug = false;
|
|
int port;
|
|
ModbusProtocol receiveData;
|
|
ModbusProtocol sendData = new ModbusProtocol();
|
|
byte[] bytes = new byte[2100];
|
|
public HoldingRegisters holdingRegisters;
|
|
public InputRegisters inputRegisters;
|
|
public Coils coils;
|
|
public DiscreteInputs discreteInputs;
|
|
private int numberOfConnections = 0;
|
|
private bool udpFlag;
|
|
private bool serialFlag;
|
|
private int baudrate = 9600;
|
|
private Parity parity = Parity.Even;
|
|
private StopBits stopBits = StopBits.One;
|
|
private string serialPort = "COM1";
|
|
private SerialPort serialport;
|
|
private byte unitIdentifier = 1;
|
|
private int portIn;
|
|
private IPAddress ipAddressIn;
|
|
private UdpClient udpClient;
|
|
private IPEndPoint iPEndPoint;
|
|
private TCPHandler tcpHandler;
|
|
Thread listenerThread;
|
|
Thread clientConnectionThread;
|
|
private ModbusProtocol[] modbusLogData = new ModbusProtocol[100];
|
|
public bool FunctionCode1Disabled { get; set; }
|
|
public bool FunctionCode2Disabled { get; set; }
|
|
public bool FunctionCode3Disabled { get; set; }
|
|
public bool FunctionCode4Disabled { get; set; }
|
|
public bool FunctionCode5Disabled { get; set; }
|
|
public bool FunctionCode6Disabled { get; set; }
|
|
public bool FunctionCode15Disabled { get; set; }
|
|
public bool FunctionCode16Disabled { get; set; }
|
|
public bool FunctionCode23Disabled { get; set; }
|
|
public bool PortChanged { get; set; }
|
|
object lockCoils = new object();
|
|
object lockHoldingRegisters = new object();
|
|
private volatile bool shouldStop;
|
|
private bool stop;
|
|
|
|
private IPAddress localIPAddress = IPAddress.Any;
|
|
|
|
/// <summary>
|
|
/// When creating a TCP or UDP socket, the local IP address to attach to.
|
|
/// </summary>
|
|
public IPAddress LocalIPAddress
|
|
{
|
|
get { return localIPAddress; }
|
|
set { if (listenerThread == null) localIPAddress = value; }
|
|
}
|
|
|
|
public ModbusServer(int port = 502)
|
|
{
|
|
this.port = port;
|
|
holdingRegisters = new HoldingRegisters(this);
|
|
inputRegisters = new InputRegisters(this);
|
|
coils = new Coils(this);
|
|
discreteInputs = new DiscreteInputs(this);
|
|
}
|
|
|
|
#region events
|
|
public delegate void CoilsChangedHandler(int coil, int numberOfCoils);
|
|
public event CoilsChangedHandler CoilsChanged;
|
|
|
|
public delegate void HoldingRegistersChangedHandler(int register, int numberOfRegisters);
|
|
public event HoldingRegistersChangedHandler HoldingRegistersChanged;
|
|
|
|
public delegate void NumberOfConnectedClientsChangedHandler();
|
|
public event NumberOfConnectedClientsChangedHandler NumberOfConnectedClientsChanged;
|
|
|
|
public delegate void LogDataChangedHandler();
|
|
public event LogDataChangedHandler LogDataChanged;
|
|
#endregion
|
|
|
|
public void Start()
|
|
{
|
|
listenerThread = new Thread(ListenerThread);
|
|
listenerThread.Start();
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
Stop();
|
|
}
|
|
public void Stop()
|
|
{
|
|
if (SerialFlag & (serialport != null))
|
|
{
|
|
if (serialport.IsOpen)
|
|
serialport.Close();
|
|
shouldStop = true;
|
|
}
|
|
try
|
|
{
|
|
tcpHandler.Disconnect();
|
|
stop = true;
|
|
listenerThread.Interrupt();
|
|
|
|
}
|
|
catch (Exception) { }
|
|
listenerThread.Join();
|
|
try
|
|
{
|
|
stop = true;
|
|
clientConnectionThread.Interrupt();
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
|
|
private void ListenerThread()
|
|
{
|
|
if (!udpFlag & !serialFlag)
|
|
{
|
|
if (udpClient != null)
|
|
{
|
|
try
|
|
{
|
|
udpClient.Close();
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
tcpHandler = new TCPHandler(LocalIPAddress, port);
|
|
if (debug) StoreLogData.Instance.Store($"EasyModbus Server listing for incomming data at Port {port}, local IP {LocalIPAddress}", System.DateTime.Now);
|
|
tcpHandler.dataChanged += new TCPHandler.DataChanged(ProcessReceivedData);
|
|
tcpHandler.numberOfClientsChanged += new TCPHandler.NumberOfClientsChanged(numberOfClientsChanged);
|
|
}
|
|
else if (serialFlag)
|
|
{
|
|
if (serialport == null)
|
|
{
|
|
if (debug) StoreLogData.Instance.Store("EasyModbus RTU-Server listing for incomming data at Serial Port " + serialPort, System.DateTime.Now);
|
|
serialport = new SerialPort();
|
|
serialport.PortName = serialPort;
|
|
serialport.BaudRate = this.baudrate;
|
|
serialport.Parity = this.parity;
|
|
serialport.StopBits = stopBits;
|
|
serialport.WriteTimeout = 10000;
|
|
serialport.ReadTimeout = 1000;
|
|
serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
|
|
serialport.Open();
|
|
}
|
|
}
|
|
else
|
|
while (!shouldStop)
|
|
{
|
|
if (stop)
|
|
break;
|
|
if (udpFlag)
|
|
{
|
|
if (udpClient == null | PortChanged)
|
|
{
|
|
IPEndPoint localEndoint = new IPEndPoint(LocalIPAddress, port);
|
|
udpClient = new UdpClient(localEndoint);
|
|
if (debug) StoreLogData.Instance.Store($"EasyModbus Server listing for incomming data at Port {port}, local IP {LocalIPAddress}", System.DateTime.Now);
|
|
udpClient.Client.ReceiveTimeout = 1000;
|
|
iPEndPoint = new IPEndPoint(IPAddress.Any, port);
|
|
PortChanged = false;
|
|
}
|
|
if (tcpHandler != null)
|
|
tcpHandler.Disconnect();
|
|
try
|
|
{
|
|
bytes = udpClient.Receive(ref iPEndPoint);
|
|
portIn = iPEndPoint.Port;
|
|
NetworkConnectionParameter networkConnectionParameter = new NetworkConnectionParameter();
|
|
networkConnectionParameter.bytes = bytes;
|
|
ipAddressIn = iPEndPoint.Address;
|
|
networkConnectionParameter.portIn = portIn;
|
|
networkConnectionParameter.ipAddressIn = ipAddressIn;
|
|
ParameterizedThreadStart pts = new ParameterizedThreadStart(this.ProcessReceivedData);
|
|
Thread processDataThread = new Thread(pts);
|
|
processDataThread.Start(networkConnectionParameter);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex is ThreadInterruptedException)
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#region SerialHandler
|
|
private bool dataReceived = false;
|
|
private byte[] readBuffer = new byte[2094];
|
|
private DateTime lastReceive;
|
|
private int nextSign = 0;
|
|
private void DataReceivedHandler(object sender,
|
|
SerialDataReceivedEventArgs e)
|
|
{
|
|
int silence = 4000 / baudrate;
|
|
if ((DateTime.Now.Ticks - lastReceive.Ticks) > TimeSpan.TicksPerMillisecond * silence)
|
|
nextSign = 0;
|
|
|
|
|
|
SerialPort sp = (SerialPort)sender;
|
|
|
|
int numbytes = sp.BytesToRead;
|
|
byte[] rxbytearray = new byte[numbytes];
|
|
|
|
sp.Read(rxbytearray, 0, numbytes);
|
|
|
|
Array.Copy(rxbytearray, 0, readBuffer, nextSign, rxbytearray.Length);
|
|
lastReceive = DateTime.Now;
|
|
nextSign = numbytes + nextSign;
|
|
if (ModbusClient.DetectValidModbusFrame(readBuffer, nextSign))
|
|
{
|
|
|
|
dataReceived = true;
|
|
nextSign = 0;
|
|
|
|
NetworkConnectionParameter networkConnectionParameter = new NetworkConnectionParameter();
|
|
networkConnectionParameter.bytes = readBuffer;
|
|
ParameterizedThreadStart pts = new ParameterizedThreadStart(this.ProcessReceivedData);
|
|
Thread processDataThread = new Thread(pts);
|
|
processDataThread.Start(networkConnectionParameter);
|
|
dataReceived = false;
|
|
|
|
}
|
|
else
|
|
dataReceived = false;
|
|
}
|
|
#endregion
|
|
|
|
#region Method numberOfClientsChanged
|
|
private void numberOfClientsChanged()
|
|
{
|
|
numberOfConnections = tcpHandler.NumberOfConnectedClients;
|
|
if (NumberOfConnectedClientsChanged != null)
|
|
NumberOfConnectedClientsChanged();
|
|
}
|
|
#endregion
|
|
|
|
object lockProcessReceivedData = new object();
|
|
#region Method ProcessReceivedData
|
|
private void ProcessReceivedData(object networkConnectionParameter)
|
|
{
|
|
lock (lockProcessReceivedData)
|
|
{
|
|
Byte[] bytes = new byte[((NetworkConnectionParameter)networkConnectionParameter).bytes.Length];
|
|
if (debug) StoreLogData.Instance.Store("Received Data: " + BitConverter.ToString(bytes), System.DateTime.Now);
|
|
NetworkStream stream = ((NetworkConnectionParameter)networkConnectionParameter).stream;
|
|
int portIn = ((NetworkConnectionParameter)networkConnectionParameter).portIn;
|
|
IPAddress ipAddressIn = ((NetworkConnectionParameter)networkConnectionParameter).ipAddressIn;
|
|
|
|
|
|
Array.Copy(((NetworkConnectionParameter)networkConnectionParameter).bytes, 0, bytes, 0, ((NetworkConnectionParameter)networkConnectionParameter).bytes.Length);
|
|
|
|
ModbusProtocol receiveDataThread = new ModbusProtocol();
|
|
ModbusProtocol sendDataThread = new ModbusProtocol();
|
|
|
|
try
|
|
{
|
|
UInt16[] wordData = new UInt16[1];
|
|
byte[] byteData = new byte[2];
|
|
receiveDataThread.timeStamp = DateTime.Now;
|
|
receiveDataThread.request = true;
|
|
if (!serialFlag)
|
|
{
|
|
//Lese Transaction identifier
|
|
byteData[1] = bytes[0];
|
|
byteData[0] = bytes[1];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.transactionIdentifier = wordData[0];
|
|
|
|
//Lese Protocol identifier
|
|
byteData[1] = bytes[2];
|
|
byteData[0] = bytes[3];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.protocolIdentifier = wordData[0];
|
|
|
|
//Lese length
|
|
byteData[1] = bytes[4];
|
|
byteData[0] = bytes[5];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.length = wordData[0];
|
|
}
|
|
|
|
//Lese unit identifier
|
|
receiveDataThread.unitIdentifier = bytes[6 - 6 * Convert.ToInt32(serialFlag)];
|
|
//Check UnitIdentifier
|
|
if ((receiveDataThread.unitIdentifier != this.unitIdentifier) & (receiveDataThread.unitIdentifier != 0))
|
|
return;
|
|
|
|
// Lese function code
|
|
receiveDataThread.functionCode = bytes[7 - 6 * Convert.ToInt32(serialFlag)];
|
|
|
|
// Lese starting address
|
|
byteData[1] = bytes[8 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[9 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.startingAdress = wordData[0];
|
|
|
|
if (receiveDataThread.functionCode <= 4)
|
|
{
|
|
// Lese quantity
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.quantity = wordData[0];
|
|
}
|
|
if (receiveDataThread.functionCode == 5)
|
|
{
|
|
receiveDataThread.receiveCoilValues = new ushort[1];
|
|
// Lese Value
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, receiveDataThread.receiveCoilValues, 0, 2);
|
|
}
|
|
if (receiveDataThread.functionCode == 6)
|
|
{
|
|
receiveDataThread.receiveRegisterValues = new ushort[1];
|
|
// Lese Value
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, receiveDataThread.receiveRegisterValues, 0, 2);
|
|
}
|
|
if (receiveDataThread.functionCode == 15)
|
|
{
|
|
// Lese quantity
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.quantity = wordData[0];
|
|
|
|
receiveDataThread.byteCount = bytes[12 - 6 * Convert.ToInt32(serialFlag)];
|
|
|
|
if ((receiveDataThread.byteCount % 2) != 0)
|
|
receiveDataThread.receiveCoilValues = new ushort[receiveDataThread.byteCount / 2 + 1];
|
|
else
|
|
receiveDataThread.receiveCoilValues = new ushort[receiveDataThread.byteCount / 2];
|
|
// Lese Value
|
|
Buffer.BlockCopy(bytes, 13 - 6 * Convert.ToInt32(serialFlag), receiveDataThread.receiveCoilValues, 0, receiveDataThread.byteCount);
|
|
}
|
|
if (receiveDataThread.functionCode == 16)
|
|
{
|
|
// Lese quantity
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.quantity = wordData[0];
|
|
|
|
receiveDataThread.byteCount = bytes[12 - 6 * Convert.ToInt32(serialFlag)];
|
|
receiveDataThread.receiveRegisterValues = new ushort[receiveDataThread.quantity];
|
|
for (int i = 0; i < receiveDataThread.quantity; i++)
|
|
{
|
|
// Lese Value
|
|
byteData[1] = bytes[13 + i * 2 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[14 + i * 2 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, receiveDataThread.receiveRegisterValues, i * 2, 2);
|
|
}
|
|
|
|
}
|
|
if (receiveDataThread.functionCode == 23)
|
|
{
|
|
// Lese starting Address Read
|
|
byteData[1] = bytes[8 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[9 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.startingAddressRead = wordData[0];
|
|
// Lese quantity Read
|
|
byteData[1] = bytes[10 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[11 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.quantityRead = wordData[0];
|
|
// Lese starting Address Write
|
|
byteData[1] = bytes[12 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[13 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.startingAddressWrite = wordData[0];
|
|
// Lese quantity Write
|
|
byteData[1] = bytes[14 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[15 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, wordData, 0, 2);
|
|
receiveDataThread.quantityWrite = wordData[0];
|
|
|
|
receiveDataThread.byteCount = bytes[16 - 6 * Convert.ToInt32(serialFlag)];
|
|
receiveDataThread.receiveRegisterValues = new ushort[receiveDataThread.quantityWrite];
|
|
for (int i = 0; i < receiveDataThread.quantityWrite; i++)
|
|
{
|
|
// Lese Value
|
|
byteData[1] = bytes[17 + i * 2 - 6 * Convert.ToInt32(serialFlag)];
|
|
byteData[0] = bytes[18 + i * 2 - 6 * Convert.ToInt32(serialFlag)];
|
|
Buffer.BlockCopy(byteData, 0, receiveDataThread.receiveRegisterValues, i * 2, 2);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{ }
|
|
this.CreateAnswer(receiveDataThread, sendDataThread, stream, portIn, ipAddressIn);
|
|
//this.sendAnswer();
|
|
this.CreateLogData(receiveDataThread, sendDataThread);
|
|
|
|
if (LogDataChanged != null)
|
|
LogDataChanged();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Method CreateAnswer
|
|
private void CreateAnswer(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
|
|
switch (receiveData.functionCode)
|
|
{
|
|
// Read Coils
|
|
case 1:
|
|
if (!FunctionCode1Disabled)
|
|
this.ReadCoils(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
break;
|
|
// Read Input Registers
|
|
case 2:
|
|
if (!FunctionCode2Disabled)
|
|
this.ReadDiscreteInputs(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Read Holding Registers
|
|
case 3:
|
|
if (!FunctionCode3Disabled)
|
|
this.ReadHoldingRegisters(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Read Input Registers
|
|
case 4:
|
|
if (!FunctionCode4Disabled)
|
|
this.ReadInputRegisters(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Write single coil
|
|
case 5:
|
|
if (!FunctionCode5Disabled)
|
|
this.WriteSingleCoil(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Write single register
|
|
case 6:
|
|
if (!FunctionCode6Disabled)
|
|
this.WriteSingleRegister(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Write Multiple coils
|
|
case 15:
|
|
if (!FunctionCode15Disabled)
|
|
this.WriteMultipleCoils(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Write Multiple registers
|
|
case 16:
|
|
if (!FunctionCode16Disabled)
|
|
this.WriteMultipleRegisters(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Error: Function Code not supported
|
|
case 23:
|
|
if (!FunctionCode23Disabled)
|
|
this.ReadWriteMultipleRegisters(receiveData, sendData, stream, portIn, ipAddressIn);
|
|
else
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
}
|
|
|
|
break;
|
|
// Error: Function Code not supported
|
|
default:
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 1;
|
|
sendException(sendData.errorCode, sendData.exceptionCode, receiveData, sendData, stream, portIn, ipAddressIn);
|
|
break;
|
|
}
|
|
sendData.timeStamp = DateTime.Now;
|
|
}
|
|
#endregion
|
|
|
|
private void ReadCoils(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
if ((receiveData.quantity < 1) | (receiveData.quantity > 0x07D0)) //Invalid quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1 + receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
if ((receiveData.quantity % 8) == 0)
|
|
sendData.byteCount = (byte)(receiveData.quantity / 8);
|
|
else
|
|
sendData.byteCount = (byte)(receiveData.quantity / 8 + 1);
|
|
|
|
sendData.sendCoilValues = new bool[receiveData.quantity];
|
|
lock (lockCoils)
|
|
Array.Copy(coils.localArray, receiveData.startingAdress + 1, sendData.sendCoilValues, 0, receiveData.quantity);
|
|
}
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
//ByteCount
|
|
data[8] = sendData.byteCount;
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendCoilValues = null;
|
|
}
|
|
|
|
if (sendData.sendCoilValues != null)
|
|
for (int i = 0; i < (sendData.byteCount); i++)
|
|
{
|
|
byteData = new byte[2];
|
|
for (int j = 0; j < 8; j++)
|
|
{
|
|
|
|
byte boolValue;
|
|
if (sendData.sendCoilValues[i * 8 + j] == true)
|
|
boolValue = 1;
|
|
else
|
|
boolValue = 0;
|
|
byteData[1] = (byte)((byteData[1]) | (boolValue << j));
|
|
if ((i * 8 + j + 1) >= sendData.sendCoilValues.Length)
|
|
break;
|
|
}
|
|
data[9 + i] = byteData[1];
|
|
}
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private void ReadDiscreteInputs(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
if ((receiveData.quantity < 1) | (receiveData.quantity > 0x07D0)) //Invalid quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1 + receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
if ((receiveData.quantity % 8) == 0)
|
|
sendData.byteCount = (byte)(receiveData.quantity / 8);
|
|
else
|
|
sendData.byteCount = (byte)(receiveData.quantity / 8 + 1);
|
|
|
|
sendData.sendCoilValues = new bool[receiveData.quantity];
|
|
Array.Copy(discreteInputs.localArray, receiveData.startingAdress + 1, sendData.sendCoilValues, 0, receiveData.quantity);
|
|
}
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
//ByteCount
|
|
data[8] = sendData.byteCount;
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendCoilValues = null;
|
|
}
|
|
|
|
if (sendData.sendCoilValues != null)
|
|
for (int i = 0; i < (sendData.byteCount); i++)
|
|
{
|
|
byteData = new byte[2];
|
|
for (int j = 0; j < 8; j++)
|
|
{
|
|
|
|
byte boolValue;
|
|
if (sendData.sendCoilValues[i * 8 + j] == true)
|
|
boolValue = 1;
|
|
else
|
|
boolValue = 0;
|
|
byteData[1] = (byte)((byteData[1]) | (boolValue << j));
|
|
if ((i * 8 + j + 1) >= sendData.sendCoilValues.Length)
|
|
break;
|
|
}
|
|
data[9 + i] = byteData[1];
|
|
}
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private void ReadHoldingRegisters(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
if ((receiveData.quantity < 1) | (receiveData.quantity > 0x007D)) //Invalid quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1 + receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
sendData.byteCount = (byte)(2 * receiveData.quantity);
|
|
sendData.sendRegisterValues = new Int16[receiveData.quantity];
|
|
lock (lockHoldingRegisters)
|
|
Buffer.BlockCopy(holdingRegisters.localArray, receiveData.startingAdress * 2 + 2, sendData.sendRegisterValues, 0, receiveData.quantity * 2);
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = (ushort)(0x03 + sendData.byteCount);
|
|
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
//ByteCount
|
|
data[8] = sendData.byteCount;
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
|
|
|
|
if (sendData.sendRegisterValues != null)
|
|
for (int i = 0; i < (sendData.byteCount / 2); i++)
|
|
{
|
|
byteData = BitConverter.GetBytes((Int16)sendData.sendRegisterValues[i]);
|
|
data[9 + i * 2] = byteData[1];
|
|
data[10 + i * 2] = byteData[0];
|
|
}
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private void ReadInputRegisters(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
if ((receiveData.quantity < 1) | (receiveData.quantity > 0x007D)) //Invalid quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1 + receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
sendData.byteCount = (byte)(2 * receiveData.quantity);
|
|
sendData.sendRegisterValues = new Int16[receiveData.quantity];
|
|
Buffer.BlockCopy(inputRegisters.localArray, receiveData.startingAdress * 2 + 2, sendData.sendRegisterValues, 0, receiveData.quantity * 2);
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = (ushort)(0x03 + sendData.byteCount);
|
|
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
//ByteCount
|
|
data[8] = sendData.byteCount;
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
|
|
|
|
if (sendData.sendRegisterValues != null)
|
|
for (int i = 0; i < (sendData.byteCount / 2); i++)
|
|
{
|
|
byteData = BitConverter.GetBytes((Int16)sendData.sendRegisterValues[i]);
|
|
data[9 + i * 2] = byteData[1];
|
|
data[10 + i * 2] = byteData[0];
|
|
}
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private void WriteSingleCoil(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
sendData.startingAdress = receiveData.startingAdress;
|
|
sendData.receiveCoilValues = receiveData.receiveCoilValues;
|
|
if ((receiveData.receiveCoilValues[0] != 0x0000) & (receiveData.receiveCoilValues[0] != 0xFF00)) //Invalid Value
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
if (receiveData.receiveCoilValues[0] == 0xFF00)
|
|
{
|
|
lock (lockCoils)
|
|
coils[receiveData.startingAdress + 1] = true;
|
|
}
|
|
if (receiveData.receiveCoilValues[0] == 0x0000)
|
|
{
|
|
lock (lockCoils)
|
|
coils[receiveData.startingAdress + 1] = false;
|
|
}
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = 0x06;
|
|
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[12 + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
else
|
|
{
|
|
byteData = BitConverter.GetBytes((int)receiveData.startingAdress);
|
|
data[8] = byteData[1];
|
|
data[9] = byteData[0];
|
|
byteData = BitConverter.GetBytes((int)receiveData.receiveCoilValues[0]);
|
|
data[10] = byteData[1];
|
|
data[11] = byteData[0];
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
if (CoilsChanged != null)
|
|
CoilsChanged(receiveData.startingAdress + 1, 1);
|
|
}
|
|
}
|
|
|
|
private void WriteSingleRegister(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
sendData.startingAdress = receiveData.startingAdress;
|
|
sendData.receiveRegisterValues = receiveData.receiveRegisterValues;
|
|
|
|
if ((receiveData.receiveRegisterValues[0] < 0x0000) | (receiveData.receiveRegisterValues[0] > 0xFFFF)) //Invalid Value
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if (((receiveData.startingAdress + 1) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
lock (lockHoldingRegisters)
|
|
holdingRegisters[receiveData.startingAdress + 1] = unchecked((ushort)receiveData.receiveRegisterValues[0]);
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = 0x06;
|
|
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[12 + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
else
|
|
{
|
|
byteData = BitConverter.GetBytes((int)receiveData.startingAdress);
|
|
data[8] = byteData[1];
|
|
data[9] = byteData[0];
|
|
byteData = BitConverter.GetBytes((int)receiveData.receiveRegisterValues[0]);
|
|
data[10] = byteData[1];
|
|
data[11] = byteData[0];
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
if (HoldingRegistersChanged != null)
|
|
HoldingRegistersChanged(receiveData.startingAdress + 1, 1);
|
|
}
|
|
}
|
|
|
|
private void WriteMultipleCoils(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
sendData.startingAdress = receiveData.startingAdress;
|
|
sendData.quantity = receiveData.quantity;
|
|
|
|
if ((receiveData.quantity == 0x0000) | (receiveData.quantity > 0x07B0)) //Invalid Quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if ((((int)receiveData.startingAdress + 1 + (int)receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
lock (lockCoils)
|
|
for (int i = 0; i < receiveData.quantity; i++)
|
|
{
|
|
int shift = i % 16;
|
|
/* if ((i == receiveData.quantity - 1) & (receiveData.quantity % 2 != 0))
|
|
{
|
|
if (shift < 8)
|
|
shift = shift + 8;
|
|
else
|
|
shift = shift - 8;
|
|
}*/
|
|
int mask = 0x1;
|
|
mask = mask << (shift);
|
|
if ((receiveData.receiveCoilValues[i / 16] & (ushort)mask) == 0)
|
|
|
|
coils[receiveData.startingAdress + i + 1] = false;
|
|
else
|
|
|
|
coils[receiveData.startingAdress + i + 1] = true;
|
|
|
|
}
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = 0x06;
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[12 + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
else
|
|
{
|
|
byteData = BitConverter.GetBytes((int)receiveData.startingAdress);
|
|
data[8] = byteData[1];
|
|
data[9] = byteData[0];
|
|
byteData = BitConverter.GetBytes((int)receiveData.quantity);
|
|
data[10] = byteData[1];
|
|
data[11] = byteData[0];
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
if (CoilsChanged != null)
|
|
CoilsChanged(receiveData.startingAdress + 1, receiveData.quantity);
|
|
}
|
|
}
|
|
|
|
private void WriteMultipleRegisters(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
sendData.startingAdress = receiveData.startingAdress;
|
|
sendData.quantity = receiveData.quantity;
|
|
|
|
if ((receiveData.quantity == 0x0000) | (receiveData.quantity > 0x07B0)) //Invalid Quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if ((((int)receiveData.startingAdress + 1 + (int)receiveData.quantity) > 65535) | (receiveData.startingAdress < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
lock (lockHoldingRegisters)
|
|
for (int i = 0; i < receiveData.quantity; i++)
|
|
{
|
|
holdingRegisters[receiveData.startingAdress + i + 1] = unchecked((ushort)receiveData.receiveRegisterValues[i]);
|
|
}
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = 0x06;
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[12 + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
else
|
|
{
|
|
byteData = BitConverter.GetBytes((int)receiveData.startingAdress);
|
|
data[8] = byteData[1];
|
|
data[9] = byteData[0];
|
|
byteData = BitConverter.GetBytes((int)receiveData.quantity);
|
|
data[10] = byteData[1];
|
|
data[11] = byteData[0];
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
if (HoldingRegistersChanged != null)
|
|
HoldingRegistersChanged(receiveData.startingAdress + 1, receiveData.quantity);
|
|
}
|
|
}
|
|
|
|
private void ReadWriteMultipleRegisters(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = this.unitIdentifier;
|
|
sendData.functionCode = receiveData.functionCode;
|
|
|
|
|
|
if ((receiveData.quantityRead < 0x0001) | (receiveData.quantityRead > 0x007D) | (receiveData.quantityWrite < 0x0001) | (receiveData.quantityWrite > 0x0079) | (receiveData.byteCount != (receiveData.quantityWrite * 2))) //Invalid Quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 3;
|
|
}
|
|
if ((((int)receiveData.startingAddressRead + 1 + (int)receiveData.quantityRead) > 65535) | (((int)receiveData.startingAddressWrite + 1 + (int)receiveData.quantityWrite) > 65535) | (receiveData.quantityWrite < 0) | (receiveData.quantityRead < 0)) //Invalid Starting adress or Starting address + quantity
|
|
{
|
|
sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
|
|
sendData.exceptionCode = 2;
|
|
}
|
|
if (sendData.exceptionCode == 0)
|
|
{
|
|
sendData.sendRegisterValues = new Int16[receiveData.quantityRead];
|
|
lock (lockHoldingRegisters)
|
|
Buffer.BlockCopy(holdingRegisters.localArray, receiveData.startingAddressRead * 2 + 2, sendData.sendRegisterValues, 0, receiveData.quantityRead * 2);
|
|
|
|
lock (holdingRegisters)
|
|
for (int i = 0; i < receiveData.quantityWrite; i++)
|
|
{
|
|
holdingRegisters[receiveData.startingAddressWrite + i + 1] = unchecked((ushort)receiveData.receiveRegisterValues[i]);
|
|
}
|
|
sendData.byteCount = (byte)(2 * receiveData.quantityRead);
|
|
}
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = Convert.ToUInt16(3 + 2 * receiveData.quantityRead);
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
|
|
Byte[] byteData = new byte[2];
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
//Function Code
|
|
data[7] = sendData.functionCode;
|
|
|
|
//ByteCount
|
|
data[8] = sendData.byteCount;
|
|
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
{
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
sendData.sendRegisterValues = null;
|
|
}
|
|
else
|
|
{
|
|
if (sendData.sendRegisterValues != null)
|
|
for (int i = 0; i < (sendData.byteCount / 2); i++)
|
|
{
|
|
byteData = BitConverter.GetBytes((Int16)sendData.sendRegisterValues[i]);
|
|
data[9 + i * 2] = byteData[1];
|
|
data[10 + i * 2] = byteData[0];
|
|
}
|
|
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
if (HoldingRegistersChanged != null)
|
|
HoldingRegistersChanged(receiveData.startingAddressWrite + 1, receiveData.quantityWrite);
|
|
}
|
|
}
|
|
|
|
private void sendException(int errorCode, int exceptionCode, ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
|
|
{
|
|
sendData.response = true;
|
|
|
|
sendData.transactionIdentifier = receiveData.transactionIdentifier;
|
|
sendData.protocolIdentifier = receiveData.protocolIdentifier;
|
|
|
|
sendData.unitIdentifier = receiveData.unitIdentifier;
|
|
sendData.errorCode = (byte)errorCode;
|
|
sendData.exceptionCode = (byte)exceptionCode;
|
|
|
|
if (sendData.exceptionCode > 0)
|
|
sendData.length = 0x03;
|
|
else
|
|
sendData.length = (ushort)(0x03 + sendData.byteCount);
|
|
|
|
if (true)
|
|
{
|
|
Byte[] data;
|
|
if (sendData.exceptionCode > 0)
|
|
data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
|
|
else
|
|
data = new byte[9 + sendData.byteCount + 2 * Convert.ToInt32(serialFlag)];
|
|
Byte[] byteData = new byte[2];
|
|
sendData.length = (byte)(data.Length - 6);
|
|
|
|
//Send Transaction identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
|
|
data[0] = byteData[1];
|
|
data[1] = byteData[0];
|
|
|
|
//Send Protocol identifier
|
|
byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
|
|
data[2] = byteData[1];
|
|
data[3] = byteData[0];
|
|
|
|
//Send length
|
|
byteData = BitConverter.GetBytes((int)sendData.length);
|
|
data[4] = byteData[1];
|
|
data[5] = byteData[0];
|
|
|
|
//Unit Identifier
|
|
data[6] = sendData.unitIdentifier;
|
|
|
|
|
|
data[7] = sendData.errorCode;
|
|
data[8] = sendData.exceptionCode;
|
|
|
|
|
|
try
|
|
{
|
|
if (serialFlag)
|
|
{
|
|
if (!serialport.IsOpen)
|
|
throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
|
|
//Create CRC
|
|
sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
|
|
byteData = BitConverter.GetBytes((int)sendData.crc);
|
|
data[data.Length - 2] = byteData[0];
|
|
data[data.Length - 1] = byteData[1];
|
|
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);
|
|
}
|
|
}
|
|
else if (udpFlag)
|
|
{
|
|
//UdpClient udpClient = new UdpClient();
|
|
IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
|
|
udpClient.Send(data, data.Length, endPoint);
|
|
|
|
}
|
|
else
|
|
{
|
|
stream.Write(data, 0, data.Length);
|
|
if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
private void CreateLogData(ModbusProtocol receiveData, ModbusProtocol sendData)
|
|
{
|
|
for (int i = 0; i < 98; i++)
|
|
{
|
|
modbusLogData[99 - i] = modbusLogData[99 - i - 2];
|
|
|
|
}
|
|
modbusLogData[0] = receiveData;
|
|
modbusLogData[1] = sendData;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int NumberOfConnections
|
|
{
|
|
get
|
|
{
|
|
return numberOfConnections;
|
|
}
|
|
}
|
|
|
|
public ModbusProtocol[] ModbusLogData
|
|
{
|
|
get
|
|
{
|
|
return modbusLogData;
|
|
}
|
|
}
|
|
|
|
public int Port
|
|
{
|
|
get
|
|
{
|
|
return port;
|
|
}
|
|
set
|
|
{
|
|
port = value;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
public bool UDPFlag
|
|
{
|
|
get
|
|
{
|
|
return udpFlag;
|
|
}
|
|
set
|
|
{
|
|
udpFlag = value;
|
|
}
|
|
}
|
|
|
|
public bool SerialFlag
|
|
{
|
|
get
|
|
{
|
|
return serialFlag;
|
|
}
|
|
set
|
|
{
|
|
serialFlag = value;
|
|
}
|
|
}
|
|
|
|
public int Baudrate
|
|
{
|
|
get
|
|
{
|
|
return baudrate;
|
|
}
|
|
set
|
|
{
|
|
baudrate = value;
|
|
}
|
|
}
|
|
|
|
public System.IO.Ports.Parity Parity
|
|
{
|
|
get
|
|
{
|
|
return parity;
|
|
}
|
|
set
|
|
{
|
|
parity = value;
|
|
}
|
|
}
|
|
|
|
public System.IO.Ports.StopBits StopBits
|
|
{
|
|
get
|
|
{
|
|
return stopBits;
|
|
}
|
|
set
|
|
{
|
|
stopBits = value;
|
|
}
|
|
}
|
|
|
|
public string SerialPort
|
|
{
|
|
get
|
|
{
|
|
return serialPort;
|
|
}
|
|
set
|
|
{
|
|
serialPort = value;
|
|
if (serialPort != null)
|
|
serialFlag = true;
|
|
else
|
|
serialFlag = false;
|
|
}
|
|
}
|
|
|
|
public byte UnitIdentifier
|
|
{
|
|
get
|
|
{
|
|
return unitIdentifier;
|
|
}
|
|
set
|
|
{
|
|
unitIdentifier = value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Gets or Sets the Filename for the LogFile
|
|
/// </summary>
|
|
public string LogFileFilename
|
|
{
|
|
get
|
|
{
|
|
return StoreLogData.Instance.Filename;
|
|
}
|
|
set
|
|
{
|
|
StoreLogData.Instance.Filename = value;
|
|
if (StoreLogData.Instance.Filename != null)
|
|
debug = true;
|
|
else
|
|
debug = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
public class HoldingRegisters
|
|
{
|
|
public ushort[] localArray = new ushort[65535];
|
|
ModbusServer modbusServer;
|
|
|
|
public HoldingRegisters(EasyModbus.ModbusServer modbusServer)
|
|
{
|
|
this.modbusServer = modbusServer;
|
|
}
|
|
|
|
public ushort this[int x]
|
|
{
|
|
get { return this.localArray[x]; }
|
|
set
|
|
{
|
|
this.localArray[x] = value;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public class InputRegisters
|
|
{
|
|
public ushort[] localArray = new ushort[65535];
|
|
ModbusServer modbusServer;
|
|
|
|
public InputRegisters(EasyModbus.ModbusServer modbusServer)
|
|
{
|
|
this.modbusServer = modbusServer;
|
|
}
|
|
|
|
public ushort this[int x]
|
|
{
|
|
get { return this.localArray[x]; }
|
|
set
|
|
{
|
|
this.localArray[x] = value;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Coils
|
|
{
|
|
public bool[] localArray = new bool[65535];
|
|
ModbusServer modbusServer;
|
|
|
|
public Coils(EasyModbus.ModbusServer modbusServer)
|
|
{
|
|
this.modbusServer = modbusServer;
|
|
}
|
|
|
|
public bool this[int x]
|
|
{
|
|
get { return this.localArray[x]; }
|
|
set
|
|
{
|
|
this.localArray[x] = value;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public class DiscreteInputs
|
|
{
|
|
public bool[] localArray = new bool[65535];
|
|
ModbusServer modbusServer;
|
|
|
|
public DiscreteInputs(EasyModbus.ModbusServer modbusServer)
|
|
{
|
|
this.modbusServer = modbusServer;
|
|
}
|
|
|
|
public bool this[int x]
|
|
{
|
|
get { return this.localArray[x]; }
|
|
set
|
|
{
|
|
this.localArray[x] = value;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
} |