diff --git a/SCADA/Example/BatchCoreTest.exe b/SCADA/Example/BatchCoreTest.exe
index c9c9adf..40bc00b 100644
Binary files a/SCADA/Example/BatchCoreTest.exe and b/SCADA/Example/BatchCoreTest.exe differ
diff --git a/SCADA/Example/ClientDriver.dll b/SCADA/Example/ClientDriver.dll
index e83bb9b..884dd00 100644
Binary files a/SCADA/Example/ClientDriver.dll and b/SCADA/Example/ClientDriver.dll differ
diff --git a/SCADA/Example/DataHelper.dll b/SCADA/Example/DataHelper.dll
index bba0fd8..6e01c14 100644
Binary files a/SCADA/Example/DataHelper.dll and b/SCADA/Example/DataHelper.dll differ
diff --git a/SCADA/Example/DataService.dll b/SCADA/Example/DataService.dll
index ce190f3..89c63d2 100644
Binary files a/SCADA/Example/DataService.dll and b/SCADA/Example/DataService.dll differ
diff --git a/SCADA/Program/DataService/Alarm.cs b/SCADA/Program/DataService/Alarm.cs
index 523fadc..a3feac5 100644
--- a/SCADA/Program/DataService/Alarm.cs
+++ b/SCADA/Program/DataService/Alarm.cs
@@ -157,67 +157,4 @@ namespace DataService
}
- [Flags]
- public enum AlarmType
- {
- None = 0,
- Level = 1,
- Dev = 2,
- Dsc = 4,
- ROC = 8,
- Quality = 16,
- Complex = 32,
- WordDsc = 64
- }
-
- [Flags]
- public enum SubAlarmType
- {
- None = 0,
- LoLo = 1,
- Low = 2,
- High = 4,
- HiHi = 8,
- MajDev = 16,
- MinDev = 32,
- Dsc = 64,
-
- BadPV = 128,
- MajROC = 256,
- MinROC = 512
- }
-
- public enum Severity
- {
- Error = 7,
- High = 6,
- MediumHigh = 5,
- Medium = 4,
- MediumLow = 3,
- Low = 2,
- Information = 1,
- Normal = 0
- }
-
- [Flags]
- public enum ConditionState : byte
- {
- Acked = 4,
- Actived = 2,
- Enabled = 1
- }
-
- public enum EventType : byte
- {
- Simple = 1,
- TraceEvent = 2,
- ConditionEvent = 4,
- }
-
- public enum ConditionType : byte
- {
- Absolute = 0,
- Percent = 1
- }
-
}
diff --git a/SCADA/Program/DataService/CacheReader.cs b/SCADA/Program/DataService/CacheReader.cs
index 45819d9..e8eb183 100644
--- a/SCADA/Program/DataService/CacheReader.cs
+++ b/SCADA/Program/DataService/CacheReader.cs
@@ -551,7 +551,7 @@ namespace DataService
public int WriteBit(DeviceAddress address, bool bit)
{
- _cache[address.CacheIndex] |= (short)(1 << address.Bit.BitSwap());
+ _cache[address.CacheIndex] |= (short)(1 << address.Bit);
return 0;
}
diff --git a/SCADA/Program/DataService/DataService.csproj b/SCADA/Program/DataService/DataService.csproj
index b811665..d77019b 100644
--- a/SCADA/Program/DataService/DataService.csproj
+++ b/SCADA/Program/DataService/DataService.csproj
@@ -158,6 +158,7 @@
+
diff --git a/SCADA/Program/DataService/DeviceAddress.cs b/SCADA/Program/DataService/DeviceAddress.cs
index 927ec42..16a2648 100644
--- a/SCADA/Program/DataService/DeviceAddress.cs
+++ b/SCADA/Program/DataService/DeviceAddress.cs
@@ -13,8 +13,9 @@ namespace DataService
public ushort CacheIndex;
public byte Bit;
public DataType VarType;
+ public ByteOrder ByteOrder;
- public DeviceAddress(int area, ushort dbnumber, ushort cIndex, int start, ushort size, byte bit, DataType type)
+ public DeviceAddress(int area, ushort dbnumber, ushort cIndex, int start, ushort size, byte bit, DataType type, ByteOrder order = ByteOrder.None)
{
Area = area;
DBNumber = dbnumber;
@@ -23,6 +24,7 @@ namespace DataService
DataSize = size;
Bit = bit;
VarType = type;
+ ByteOrder = order;
}
public static readonly DeviceAddress Empty = new DeviceAddress(0, 0, 0, 0, 0, 0, DataType.NONE);
diff --git a/SCADA/Program/DataService/Enums.cs b/SCADA/Program/DataService/Enums.cs
new file mode 100644
index 0000000..ce7b7c1
--- /dev/null
+++ b/SCADA/Program/DataService/Enums.cs
@@ -0,0 +1,99 @@
+using System;
+
+namespace DataService
+{
+
+ public enum DataSource
+ {
+ Cache = 1,
+ Device = 2
+ }
+
+ public enum DataType : byte
+ {
+ NONE = 0,
+ BOOL = 1,
+ BYTE = 3,
+ SHORT = 4,
+ WORD = 5,
+ TIME = 6,
+ INT = 7,
+ FLOAT = 8,
+ SYS = 9,
+ STR = 11
+ }
+
+ [Flags]
+ public enum ByteOrder : byte
+ {
+ None = 0,
+ BigEndian = 1,
+ LittleEndian = 2,
+ Network = 4,
+ Host = 8
+ }
+
+
+ [Flags]
+ public enum AlarmType
+ {
+ None = 0,
+ Level = 1,
+ Dev = 2,
+ Dsc = 4,
+ ROC = 8,
+ Quality = 16,
+ Complex = 32,
+ WordDsc = 64
+ }
+
+ [Flags]
+ public enum SubAlarmType
+ {
+ None = 0,
+ LoLo = 1,
+ Low = 2,
+ High = 4,
+ HiHi = 8,
+ MajDev = 16,
+ MinDev = 32,
+ Dsc = 64,
+
+ BadPV = 128,
+ MajROC = 256,
+ MinROC = 512
+ }
+
+ public enum Severity
+ {
+ Error = 7,
+ High = 6,
+ MediumHigh = 5,
+ Medium = 4,
+ MediumLow = 3,
+ Low = 2,
+ Information = 1,
+ Normal = 0
+ }
+
+ [Flags]
+ public enum ConditionState : byte
+ {
+ Acked = 4,
+ Actived = 2,
+ Enabled = 1
+ }
+
+ public enum EventType : byte
+ {
+ Simple = 1,
+ TraceEvent = 2,
+ ConditionEvent = 4,
+ }
+
+ public enum ConditionType : byte
+ {
+ Absolute = 0,
+ Percent = 1
+ }
+}
diff --git a/SCADA/Program/DataService/ITag.cs b/SCADA/Program/DataService/ITag.cs
index a08c8df..f9f314d 100644
--- a/SCADA/Program/DataService/ITag.cs
+++ b/SCADA/Program/DataService/ITag.cs
@@ -579,26 +579,6 @@ namespace DataService
}
}
- public enum DataSource
- {
- Cache = 1,
- Device = 2
- }
-
- public enum DataType : byte
- {
- NONE = 0,
- BOOL = 1,
- BYTE = 3,
- SHORT = 4,
- WORD = 5,
- TIME = 6,
- INT = 7,
- FLOAT = 8,
- SYS = 9,
- STR = 11
- }
-
public delegate void ValueChangingEventHandler(object sender, ValueChangingEventArgs e);
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
diff --git a/SCADA/Program/DataService/PLCGroup.cs b/SCADA/Program/DataService/PLCGroup.cs
index 0040a54..a125ae2 100644
--- a/SCADA/Program/DataService/PLCGroup.cs
+++ b/SCADA/Program/DataService/PLCGroup.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Net;
using System.Timers;
namespace DataService
@@ -683,4 +684,278 @@ namespace DataService
Count = count;
}
}
+
+ public sealed class NetBytePLCGroup : PLCGroup
+ {
+ public NetBytePLCGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
+ {
+ this._id = id;
+ this._name = name;
+ this._updateRate = updateRate;
+ this._isActive = active;
+ this._plcReader = plcReader;
+ this._server = _plcReader.Parent;
+ this._timer = new Timer();
+ this._changedList = new List();
+ this._cacheReader = new NetByteCacheReader();
+ }
+
+ protected override void Poll()
+ {
+ if (_items == null || _items.Count == 0) return;
+ byte[] cache = (byte[])_cacheReader.Cache;
+ int offset = 0;
+ foreach (PDUArea area in _rangeList)
+ {
+ byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
+ if (rcvBytes == null)
+ {
+ //_plcReader.Connect();
+ continue;
+ }
+ else
+ {
+ int index = area.StartIndex;//index指向_items中的Tag元数据
+ int count = index + area.Count;
+ while (index < count)
+ {
+ DeviceAddress addr = _items[index].Address;
+ int iByte = addr.CacheIndex;
+ int iByte1 = iByte - offset;
+ if (addr.VarType == DataType.BOOL)
+ {
+ int tmp = rcvBytes[iByte1] ^ cache[iByte];
+ DeviceAddress next = addr;
+ if (tmp != 0)
+ {
+ while (addr.Start == next.Start)
+ {
+ if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
+ if (++index < count)
+ next = _items[index].Address;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while (addr.Start == next.Start && ++index < count)
+ {
+ next = _items[index].Address;
+ }
+ }
+ }
+ else
+ {
+ ushort size = addr.DataSize;
+ for (int i = 0; i < size; i++)
+ {
+ if (iByte1 + i < rcvBytes.Length && rcvBytes[iByte1 + i] != cache[iByte + i])
+ {
+ _changedList.Add(index);
+ break;
+ }
+ }
+ index++;
+ }
+ }
+ for (int j = 0; j < rcvBytes.Length; j++)
+ cache[j + offset] = rcvBytes[j];//将PLC读取的数据写入到CacheReader中
+ }
+ offset += rcvBytes.Length;
+ }
+ }
+ }
+
+ public sealed class NetShortGroup : PLCGroup
+ {
+ public NetShortGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
+ {
+ this._id = id;
+ this._name = name;
+ this._updateRate = updateRate;
+ this._isActive = active;
+ this._plcReader = plcReader;
+ this._server = _plcReader.Parent;
+ this._timer = new Timer();
+ this._changedList = new List();
+ this._cacheReader = new NetShortCacheReader();
+ }
+
+ protected override unsafe void Poll()
+ {
+ short[] cache = (short[])_cacheReader.Cache;
+ int offset = 0;
+ foreach (PDUArea area in _rangeList)
+ {
+ byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
+ if (rcvBytes == null || rcvBytes.Length == 0)
+ {
+ offset += (area.Len + 1) / 2;
+ //_plcReader.Connect();
+ continue;
+ }
+ else
+ {
+ int len = rcvBytes.Length / 2;
+ fixed (byte* p1 = rcvBytes)
+ {
+ short* prcv = (short*)p1;
+ int index = area.StartIndex;//index指向_items中的Tag元数据
+ int count = index + area.Count;
+ while (index < count)
+ {
+ DeviceAddress addr = _items[index].Address;
+ int iShort = addr.CacheIndex;
+ int iShort1 = iShort - offset;
+ if (addr.VarType == DataType.BOOL)
+ {
+ if (addr.ByteOrder.HasFlag(ByteOrder.Network)) prcv[iShort1] = IPAddress.HostToNetworkOrder(prcv[iShort1]);
+ int tmp = prcv[iShort1] ^ cache[iShort];
+ DeviceAddress next = addr;
+ if (tmp != 0)
+ {
+ while (addr.Start == next.Start)
+ {
+ if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
+ if (++index < count)
+ next = _items[index].Address;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while (addr.Start == next.Start && ++index < count)
+ {
+ next = _items[index].Address;
+ }
+ }
+ }
+ else
+ {
+ if (addr.DataSize <= 2)
+ {
+ if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
+ }
+ else
+ {
+ int size = addr.DataSize / 2;
+ for (int i = 0; i < size; i++)
+ {
+ if (prcv[iShort1 + i] != cache[iShort + i])
+ {
+ _changedList.Add(index);
+ break;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ for (int j = 0; j < len; j++)
+ {
+ cache[j + offset] = prcv[j];
+ }//将PLC读取的数据写入到CacheReader中
+ }
+ offset += len;
+ }
+ }
+ }
+ }
+
+ public sealed class ShortGroup : PLCGroup
+ {
+ public ShortGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
+ {
+ this._id = id;
+ this._name = name;
+ this._updateRate = updateRate;
+ this._isActive = active;
+ this._plcReader = plcReader;
+ this._server = _plcReader.Parent;
+ this._timer = new Timer();
+ this._changedList = new List();
+ this._cacheReader = new ShortCacheReader();
+ }
+
+ protected override unsafe void Poll()
+ {
+ short[] cache = (short[])_cacheReader.Cache;
+ int k = 0;
+ foreach (PDUArea area in _rangeList)
+ {
+ byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
+ if (rcvBytes == null)
+ {
+ continue;
+ }
+ else
+ {
+ int len = rcvBytes.Length / 2;
+ fixed (byte* p1 = rcvBytes)
+ {
+ short* prcv = (short*)p1;
+ int index = area.StartIndex;//index指向_items中的Tag元数据
+ int count = index + area.Count;
+ while (index < count)
+ {
+ DeviceAddress addr = _items[index].Address;
+ int iShort = addr.CacheIndex;
+ int iShort1 = iShort - k;
+ if (addr.VarType == DataType.BOOL)
+ {
+ int tmp = prcv[iShort1] ^ cache[iShort];
+ DeviceAddress next = addr;
+ if (tmp != 0)
+ {
+ while (addr.Start == next.Start)
+ {
+ if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
+ if (++index < count)
+ next = _items[index].Address;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while (addr.Start == next.Start && ++index < count)
+ {
+ next = _items[index].Address;
+ }
+ }
+ }
+ else
+ {
+ if (addr.DataSize <= 2)
+ {
+ if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
+ }
+ else
+ {
+ int size = addr.DataSize / 2;
+ for (int i = 0; i < size; i++)
+ {
+ if (prcv[iShort1 + i] != cache[iShort + i])
+ {
+ _changedList.Add(index);
+ break;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ for (int j = 0; j < len; j++)
+ {
+ cache[j + k] = prcv[j];
+ }//将PLC读取的数据写入到CacheReader中
+ }
+ k += len;
+ }
+ }
+ }
+
+ }
}
diff --git a/SCADA/Program/ModbusDriver/ModbusDriver.csproj b/SCADA/Program/ModbusDriver/ModbusDriver.csproj
index d57f61d..afea990 100644
--- a/SCADA/Program/ModbusDriver/ModbusDriver.csproj
+++ b/SCADA/Program/ModbusDriver/ModbusDriver.csproj
@@ -104,7 +104,6 @@
-
diff --git a/SCADA/Program/ModbusDriver/ModbusRTUDriver.cs b/SCADA/Program/ModbusDriver/ModbusRTUDriver.cs
index dc6a133..4c856ba 100644
--- a/SCADA/Program/ModbusDriver/ModbusRTUDriver.cs
+++ b/SCADA/Program/ModbusDriver/ModbusRTUDriver.cs
@@ -84,7 +84,7 @@ namespace ModbusDriver
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
- ModbusRtuGroup grp = new ModbusRtuGroup(id, name, updateRate, active, this);
+ ShortGroup grp = new ShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
@@ -151,8 +151,8 @@ namespace ModbusDriver
data[0] = _slaveId; // Slave id high byte
data[1] = Modbus.fctWriteSingleCoil; // Function code
byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
+ data[2] = _adr[1]; // Start address
+ data[3] = _adr[0]; // Start address
if (OnOff) data[4] = 0xFF;
byte[] arr = Utility.CalculateCrc(data, 6);
data[6] = arr[0];
@@ -169,11 +169,11 @@ namespace ModbusDriver
data[0] = _slaveId; // Slave id high byte 从站地址高八位
data[1] = Modbus.fctWriteMultipleCoils; // Function code 功能码
byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address 开始地址高八位
- data[3] = _adr[1]; // Start address 开始地址低八位
+ data[2] = _adr[1]; // Start address 开始地址高八位
+ data[3] = _adr[0]; // Start address 开始地址低八位
byte[] _length = BitConverter.GetBytes((short)numBits);
- data[4] = _length[0]; // Number of data to read 寄存器数量高八位
- data[5] = _length[1]; // Number of data to read 寄存器数量低八位
+ data[4] = _length[1]; // Number of data to read 寄存器数量高八位
+ data[5] = _length[0]; // Number of data to read 寄存器数量低八位
data[6] = (byte)len; //字节数量
Array.Copy(values, 0, data, 7, len); //在data中加入变更数据
byte[] arr = Utility.CalculateCrc(data, len + 7);
@@ -190,10 +190,10 @@ namespace ModbusDriver
data[0] = _slaveId; // Slave id high byte 从站地址高八位
data[1] = Modbus.fctWriteSingleRegister; // Function code 功能码
byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address 开始地址高八位
- data[3] = _adr[1]; // Start address 开始地址高八位
- data[4] = values[0]; //变更数据的高位
- data[5] = values[1]; //变更数据的低位
+ data[2] = _adr[1]; // Start address 开始地址高八位
+ data[3] = _adr[0]; // Start address 开始地址高八位
+ data[4] = values[1]; //变更数据的高位
+ data[5] = values[0]; //变更数据的低位
byte[] arr = Utility.CalculateCrc(data, 6);
data[6] = arr[0]; //CRC校验码低八位
data[7] = arr[1]; //CRC校验码高八位
@@ -210,11 +210,11 @@ namespace ModbusDriver
data[0] = _slaveId; // Slave id high byte 从站地址
data[1] = Modbus.fctWriteMultipleRegister; // Function code 功能码
byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address 开始地址高八位
- data[3] = _adr[1]; // Start address 开始地址低八位
+ data[2] = _adr[1]; // Start address 开始地址高八位
+ data[3] = _adr[0]; // Start address 开始地址低八位
byte[] _length = BitConverter.GetBytes((short)(len >> 1));
- data[4] = _length[0]; // Number of data to read 寄存器数量高八位
- data[5] = _length[1]; // Number of data to read 寄存器数量低八位
+ data[4] = _length[1]; // Number of data to read 寄存器数量高八位
+ data[5] = _length[0]; // Number of data to read 寄存器数量低八位
data[6] = (byte)len; //字节数
Array.Copy(values, 0, data, 7, len); //把变更数据加入data中
byte[] arr = Utility.CalculateCrc(data, len + 7);
@@ -247,43 +247,37 @@ namespace ModbusDriver
set { _slaveId = value; }
}
- public DeviceAddress GetDeviceAddress(string address)//PLC地址一般为5位 如40001,也有可能为40001.1 首位代表地址类型
+ public DeviceAddress GetDeviceAddress(string address)
{
DeviceAddress dv = DeviceAddress.Empty;
if (string.IsNullOrEmpty(address))
return dv;
switch (address[0])
{
- case '0'://功能码:01 读线圈或离散量输出状态 00001 - 09999:数字量输出( 线圈)
+ case '0':
{
dv.Area = Modbus.fctReadCoil;
int st;
int.TryParse(address, out st);
- //delete : if st<16, execute st /= 16, st will equal 0, in func ReadBytes() address.Start * 16 has no effect
- //dv.Bit = (byte)(st % 16);
- //st /= 16;
+ dv.Bit = (byte)(st % 16);
+ st /= 16;
dv.Start = st;
- //add : use PLC address(base 1)
- dv.Start--;
}
break;
- case '1'://功能码:02 读离散量输入 10001 - 19999:数字量输入(触点)
+ case '1':
{
dv.Area = Modbus.fctReadDiscreteInputs;
int st;
int.TryParse(address.Substring(1), out st);
- //delete : if st<16, execute st /= 16, st will equal 0, in func ReadBytes() address.Start * 16 has no effect
- //dv.Bit = (byte)(st % 16);
- //st /= 16;
+ dv.Bit = (byte)(st % 16);
+ st /= 16;
dv.Start = st;
- //add : use PLC address(base 1)
- dv.Start--;
}
- break;
+ break;
case '4':
{
int index = address.IndexOf('.');
- dv.Area = Modbus.fctReadHoldingRegister;//功能码:03 读取保持寄存器 40001 - 49999:数据保持寄存器
+ dv.Area = Modbus.fctReadHoldingRegister;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
@@ -291,13 +285,13 @@ namespace ModbusDriver
}
else
dv.Start = int.Parse(address.Substring(1));
- dv.Start--; //PLC的寄存器地址比modbus协议的通讯地址大1 如:40002 对应寻 址地址 0x0001
+ dv.Start--;
}
break;
case '3':
{
int index = address.IndexOf('.');
- dv.Area = Modbus.fctReadInputRegister;//功能码:04读输入寄存器 30001 - 39999:输入数据寄存器(通常为模拟量输入)
+ dv.Area = Modbus.fctReadInputRegister;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
@@ -305,10 +299,11 @@ namespace ModbusDriver
}
else
dv.Start = int.Parse(address.Substring(1));
- dv.Start--; //PLC的寄存器地址比modbus协议的通讯地址大1 如:40002 对应寻 址地址 0x0001
+ dv.Start--;
}
break;
}
+ dv.Bit--;
return dv;
}
@@ -323,53 +318,31 @@ namespace ModbusDriver
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
int area = address.Area;
-
- //no need to multiply by 16
- //byte[] header = area == Modbus.fctReadCoil ? CreateReadHeader(address.Start * 16, (ushort)(16 * size), (byte)area) :
- // CreateReadHeader(address.Start, size, (byte)area);
- byte[] header = CreateReadHeader(address.Start, size, (byte)area);
- lock (_async)
+ try
{
- try
+ byte[] header = area == Modbus.fctReadCoil ? CreateReadHeader(address.Start * 16, (ushort)(16 * size), (byte)area) :
+ CreateReadHeader(address.Start, size, (byte)area);
+ _serialPort.Write(header, 0, header.Length);
+ byte[] frameBytes = new byte[size * 2 + 5];
+ byte[] data = new byte[size * 2];
+ int numBytesRead = 0;
+ lock (_async)
{
- _serialPort.Write(header, 0, header.Length);
- /* different function_code have different realy frameBytes
- * function_code 1/2: one register variable use one bit
- * function_code 3/4: one register variable use two bytes
- */
- int modbus_rtu_replay_frameBytes_size = 0;
- int modbus_rtu_replay_data_size = 0;
- switch (area)
- {
- case 1:
- case 2:
- modbus_rtu_replay_frameBytes_size = size / 8 + 1 + 5;
- break;
- case 3:
- case 4:
- modbus_rtu_replay_frameBytes_size = size * 2 + 5;
- break;
- }
- modbus_rtu_replay_data_size = modbus_rtu_replay_frameBytes_size - 5;
-
- byte[] frameBytes = new byte[modbus_rtu_replay_frameBytes_size];
- byte[] data = new byte[modbus_rtu_replay_data_size];
- int numBytesRead = 0;
- while (numBytesRead != modbus_rtu_replay_frameBytes_size)
- numBytesRead += _serialPort.Read(frameBytes, numBytesRead, modbus_rtu_replay_frameBytes_size - numBytesRead);
+ while (numBytesRead != frameBytes.Length)
+ numBytesRead += _serialPort.Read(frameBytes, numBytesRead, frameBytes.Length - numBytesRead);
if (frameBytes[0] == _slaveId && Utility.CheckSumCRC(frameBytes))
{
- Array.Copy(frameBytes, 3, data, 0, modbus_rtu_replay_data_size);
+ Array.Copy(frameBytes, 3, data, 0, data.Length);
return data;
}
- return null;
- }
- catch (Exception e)
- {
- if (OnClose != null)
- OnClose(this, new ShutdownRequestEventArgs(e.Message));
- return null;
}
+ return null;
+ }
+ catch (Exception e)
+ {
+ if (OnClose != null)
+ OnClose(this, new ShutdownRequestEventArgs(e.Message));
+ return null;
}
}
@@ -503,146 +476,6 @@ namespace ModbusDriver
#endregion
}
- public sealed class ModbusRtuGroup : PLCGroup
- {
- public ModbusRtuGroup(short id, string name, int updateRate, bool active, ModbusRTUReader plcReader)
- {
- this._id = id;
- this._name = name;
- this._updateRate = updateRate;
- this._isActive = active;
- this._plcReader = plcReader;
- this._server = _plcReader.Parent;
- this._timer = new Timer();
- this._changedList = new List();
- this._cacheReader = new ShortCacheReader();
- }
-
- protected override unsafe void Poll()
- {
- short[] cache = (short[])_cacheReader.Cache;
- int k = 0;
- foreach (PDUArea area in _rangeList)
- {
- byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
- if (rcvBytes == null)
- {
- continue;
- }
- else
- {
- //function code = 01 or 02
- if ((area.Start.Area == 1) || (area.Start.Area == 2))
- {
- fixed (byte* p1_coil = rcvBytes)
- {
- byte* prcv_coil = p1_coil;
- int index = area.StartIndex;//index指向_items中的Tag元数据
- int count = index + area.Count;
- int len = rcvBytes.Length;
- for (int rcvBytes_index = 0; rcvBytes_index < len; rcvBytes_index++) //for index whitch byte
- {
- for (int rcvBytes_bit_index = 0; rcvBytes_bit_index < 8; rcvBytes_bit_index++) //for index whitch bit
- {
- short change_flag = 0;
- if ((prcv_coil[rcvBytes_index] & (0x01 << rcvBytes_bit_index)) != 0)
- {
- change_flag = 1;
- }
- int tmp = change_flag ^ cache[index];
- if (tmp != 0)
- {
- _changedList.Add(index);
- cache[index] = change_flag;
- }
- index++;
- if (index >= count)
- {
- break;
- }
- }
- }
- }
- }
- else //function code = 03 or 04
- {
- #region apply on small endian, if you are big endian, no need to do this
- byte exchange_temp;
- for (int index = 0; index < rcvBytes.Length; index = index + 2)
- {
- exchange_temp = rcvBytes[index + 1];
- rcvBytes[index + 1] = rcvBytes[index];
- rcvBytes[index] = exchange_temp;
- }
- #endregion
-
- int len = rcvBytes.Length / 2;
- fixed (byte* p1 = rcvBytes)
- {
- short* prcv = (short*)p1;
- int index = area.StartIndex;//index指向_items中的Tag元数据
- int count = index + area.Count;
- while (index < count)
- {
- DeviceAddress addr = _items[index].Address;
- int iShort = addr.CacheIndex;
- int iShort1 = iShort - k;
- if (addr.VarType == DataType.BOOL)
- {
- int tmp = prcv[iShort1] ^ cache[iShort];
- DeviceAddress next = addr;
- if (tmp != 0)
- {
- while (addr.Start == next.Start)
- {
- if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
- if (++index < count)
- next = _items[index].Address;
- else
- break;
- }
- }
- else
- {
- while (addr.Start == next.Start && ++index < count)
- {
- next = _items[index].Address;
- }
- }
- }
- else
- {
- if (addr.DataSize <= 2)
- {
- if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
- }
- else
- {
- int size = addr.DataSize / 2;
- for (int i = 0; i < size; i++)
- {
- if (prcv[iShort1 + i] != cache[iShort + i])
- {
- _changedList.Add(index);
- break;
- }
- }
- }
- index++;
- }
- }
- for (int j = 0; j < len; j++)
- {
- cache[j + k] = prcv[j];
- }//将PLC读取的数据写入到CacheReader中
- }
- k += len;
- }
- }
- }
- }
- }
-
public sealed class Modbus
{
diff --git a/SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs b/SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs
deleted file mode 100644
index e8243f0..0000000
--- a/SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs
+++ /dev/null
@@ -1,462 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Net.Sockets;
-using System.Text;
-using DataService;
-
-namespace ModbusDriver
-{
- [Description("Modbus RTU_TCP协议")]
- public sealed class ModbusRTU_TCPReader : IPLCDriver, IMultiReadWrite
- {
- private int _timeout;
-
- private Socket tcpSynCl;
- private byte[] tcpSynClBuffer = new byte[0xFF];
-
- short _id;
- public short ID
- {
- get
- {
- return _id;
- }
- }
-
- string _name;
- public string Name
- {
- get
- {
- return _name;
- }
- }
-
- int _slave = 1;
- string _ip;
- public string ServerName
- {
- get { return _ip; }
- set { _ip = value; }
- }
-
- public bool IsClosed
- {
- get
- {
- return tcpSynCl == null || tcpSynCl.Connected == false;
- }
- }
-
- public int TimeOut
- {
- get { return _timeout; }
- set { _timeout = value; }
- }
-
- List _grps = new List(20);
- public IEnumerable Groups
- {
- get { return _grps; }
- }
-
- IDataServer _server;
- public IDataServer Parent
- {
- get { return _server; }
- }
-
- public ModbusRTU_TCPReader(IDataServer server, short id, string name, string ip, int timeOut = 500, string spare1 = "1", string spare2 = null)
- {
- _id = id;//id
- _name = name;
- _server = server;
- _ip = ip;
- _timeout = timeOut;
- if (!string.IsNullOrEmpty(spare1))
- _slave = int.Parse(spare1);
- }
-
- public bool Connect()
- {
- int port = 7000;
- try
- {
- if (tcpSynCl != null)
- tcpSynCl.Close();
- //IPAddress ip = IPAddress.Parse(_ip);
- // ----------------------------------------------------------------
- // Connect synchronous client
- tcpSynCl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- tcpSynCl.SendTimeout = _timeout;
- tcpSynCl.ReceiveTimeout = _timeout;
- tcpSynCl.NoDelay = true;
- tcpSynCl.Connect(_ip, port);
- return true;
- }
- catch (SocketException error)
- {
- if (OnClose != null)
- OnClose(this, new ShutdownRequestEventArgs(error.Message));
- return false;
- }
- }
-
- private byte[] CreateReadHeader(int startAddress, ushort length, byte function)
- {
- byte[] data = new byte[8];
- data[0] = (byte)_slave; // Slave id high byte
- data[1] = function; // Message size
- byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
- byte[] _length = BitConverter.GetBytes((short)length);
- data[4] = _length[0]; // Number of data to read
- data[5] = _length[1]; // Number of data to read
- byte[] arr = Utility.CalculateCrc(data, 6);
- data[6] = arr[0];
- data[7] = arr[1];
- return data;
- }
-
- public byte[] WriteSingleCoils(int startAddress, bool OnOff)
- {
- byte[] data = new byte[8];
- data[0] = (byte)_slave; // Slave id high byte
- data[1] = Modbus.fctWriteSingleCoil; // Function code
- byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
- if (OnOff) data[4] = 0xFF;
- byte[] arr = Utility.CalculateCrc(data, 6);
- data[6] = arr[0];
- data[7] = arr[1];
- return data;
- }
-
- public byte[] WriteMultipleCoils(int startAddress, ushort numBits, byte[] values)
- {
- int len = values.Length;
- byte[] data = new byte[len + 9];
- data[0] = (byte)_slave; // Slave id high byte
- data[1] = Modbus.fctWriteMultipleCoils; // Function code
- byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
- byte[] _length = BitConverter.GetBytes((short)numBits);
- data[4] = _length[0]; // Number of data to read
- data[5] = _length[1]; // Number of data to read
- data[6] = (byte)len;
- Array.Copy(values, 0, data, 7, len);
- byte[] arr = Utility.CalculateCrc(data, len + 7);
- data[len + 7] = arr[0];
- data[len + 8] = arr[1];
- return data;
- }
-
- public byte[] WriteSingleRegister(int startAddress, byte[] values)
- {
- byte[] data = new byte[8];
- data[0] = (byte)_slave; // Slave id high byte
- data[1] = Modbus.fctWriteSingleRegister; // Function code
- byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
- data[4] = values[0];
- data[5] = values[1];
- byte[] arr = Utility.CalculateCrc(data, 6);
- data[6] = arr[0];
- data[7] = arr[1];
- return data;
- }
-
- public byte[] WriteMultipleRegister(int startAddress, byte[] values)
- {
- int len = values.Length;
- if (len % 2 > 0) len++;
- byte[] data = new byte[len + 9];
- data[0] = (byte)_slave; // Slave id high byte
- data[1] = Modbus.fctWriteMultipleRegister; // Function code
- byte[] _adr = BitConverter.GetBytes((short)startAddress);
- data[2] = _adr[0]; // Start address
- data[3] = _adr[1]; // Start address
- byte[] _length = BitConverter.GetBytes((short)(len >> 1));
- data[4] = _length[0]; // Number of data to read
- data[5] = _length[1]; // Number of data to read
- data[6] = (byte)len;
- Array.Copy(values, 0, data, 7, len);
- byte[] arr = Utility.CalculateCrc(data, len + 7);
- data[len + 7] = arr[0];
- data[len + 8] = arr[1];
- return data;
- }
-
- public int PDU
- {
- get { return 252; }
- //get { return 256; }
- }
-
- public DeviceAddress GetDeviceAddress(string address)
- {
- DeviceAddress dv = DeviceAddress.Empty;
- if (string.IsNullOrEmpty(address))
- return dv;
- switch (address[0])
- {
- case '0':
- {
- dv.Area = Modbus.fctReadCoil;
- int st;
- int.TryParse(address, out st);
- //dv.Start = (st / 16) * 16;//???????????????????
- dv.Bit = (byte)(st % 16);
- st /= 16;
- dv.Start = st;
- }
- break;
- case '1':
- {
- dv.Area = Modbus.fctReadDiscreteInputs;
- int st;
- int.TryParse(address.Substring(1), out st);
- //dv.Start = (st / 16) * 16;//???????????????????
- dv.Bit = (byte)(st % 16);
- st /= 16;
- dv.Start = st;
- }
- break;
- case '4':
- {
- int index = address.IndexOf('.');
- dv.Area = Modbus.fctReadHoldingRegister;
- if (index > 0)
- {
- dv.Start = int.Parse(address.Substring(1, index - 1));
- dv.Bit = byte.Parse(address.Substring(index + 1));
- }
- else
- dv.Start = int.Parse(address.Substring(1));
- dv.Start--;
- }
- break;
- case '3':
- {
- int index = address.IndexOf('.');
- dv.Area = Modbus.fctReadInputRegister;
- if (index > 0)
- {
- dv.Start = int.Parse(address.Substring(1, index - 1));
- dv.Bit = byte.Parse(address.Substring(index + 1));
- }
- else
- dv.Start = int.Parse(address.Substring(1));
- dv.Start--;
- }
- break;
- }
- return dv;
- }
-
- public string GetAddress(DeviceAddress address)
- {
- return string.Empty;
- }
-
-
- public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
- {
- ModbusTcpGroup grp = new ModbusTcpGroup(id, name, updateRate, active, this);
- _grps.Add(grp);
- return grp;
- }
-
- public bool RemoveGroup(IGroup grp)
- {
- grp.IsActive = false;
- return _grps.Remove(grp);
- }
-
- public void Dispose()
- {
- if (tcpSynCl != null)
- {
- if (tcpSynCl.Connected)
- {
- try { tcpSynCl.Shutdown(SocketShutdown.Both); }
- catch { }
- tcpSynCl.Close();
- }
- tcpSynCl = null;
- }
- foreach (IGroup grp in _grps)
- {
- grp.Dispose();
- }
- _grps.Clear();
- }
-
- public byte[] ReadBytes(DeviceAddress address, ushort size)
- {
- int area = address.Area;
- try
- {
- if (!tcpSynCl.Connected) return null;
- byte[] header = area == Modbus.fctReadCoil ? CreateReadHeader(address.Start * 16, (ushort)(16 * size), (byte)area) :
- CreateReadHeader(address.Start, size, (byte)area);
- tcpSynCl.Send(header, 0, header.Length, SocketFlags.None);//是否存在lock的问题?
- byte[] frameBytes = new byte[size * 2 + 3];
- int result = tcpSynCl.Receive(frameBytes, 0, frameBytes.Length, SocketFlags.None);
- byte[] data = new byte[size * 2];
- if (frameBytes[0] == (byte)_slave)
- {
- Array.Copy(frameBytes, 3, data, 0, data.Length);
- return data;
- }
- else return new byte[0];
- }
- catch (Exception e)
- {
- if (OnClose != null)
- OnClose(this, new ShutdownRequestEventArgs(e.Message));
- return null;
- }
- }
-
- public ItemData ReadInt32(DeviceAddress address)
- {
- byte[] bit = ReadBytes(address, 2);
- return bit == null ? new ItemData(0, 0, QUALITIES.QUALITY_BAD) :
- new ItemData(BitConverter.ToInt32(bit, 0), 0, QUALITIES.QUALITY_GOOD);
- }
-
- public ItemData ReadInt16(DeviceAddress address)
- {
- byte[] bit = ReadBytes(address, 1);
- return bit == null ? new ItemData(0, 0, QUALITIES.QUALITY_BAD) :
- new ItemData(BitConverter.ToInt16(bit, 0), 0, QUALITIES.QUALITY_GOOD);
- }
-
- public ItemData ReadByte(DeviceAddress address)
- {
- byte[] bit = ReadBytes(address, 1);
- return bit == null ? new ItemData(0, 0, QUALITIES.QUALITY_BAD) :
- new ItemData(bit[0], 0, QUALITIES.QUALITY_GOOD);
- }
-
- public ItemData ReadString(DeviceAddress address, ushort size)
- {
- byte[] bit = ReadBytes(address, size);
- return bit == null ? new ItemData(string.Empty, 0, QUALITIES.QUALITY_BAD) :
- new ItemData(Encoding.ASCII.GetString(bit), 0, QUALITIES.QUALITY_GOOD);
- }
-
- public unsafe ItemData ReadFloat(DeviceAddress address)
- {
- byte[] bit = ReadBytes(address, 2);
- return bit == null ? new ItemData(0f, 0, QUALITIES.QUALITY_BAD) :
- new ItemData(BitConverter.ToSingle(bit, 0), 0, QUALITIES.QUALITY_GOOD);
- //int value = BitConverter.ToInt32(bit, 0);
- //return new ItemData(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD);
- }
-
- public ItemData ReadBit(DeviceAddress address)
- {
- byte[] bit = ReadBytes(address, 1);
- return bit == null ? new ItemData(false, 0, QUALITIES.QUALITY_BAD) :
- new ItemData((bit[0] & (1 << (address.Bit))) > 0, 0, QUALITIES.QUALITY_GOOD);
- }
-
- public ItemData