Browse Source

Merge pull request #1 from GavinYellow/master

修复bug
pull/17/head
zhangfl0220 9 years ago
committed by GitHub
parent
commit
5b3027cd5a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. BIN
      SCADA/Example/BatchCoreTest.exe
  2. BIN
      SCADA/Example/ClientDriver.dll
  3. BIN
      SCADA/Example/DataHelper.dll
  4. BIN
      SCADA/Example/DataService.dll
  5. 63
      SCADA/Program/DataService/Alarm.cs
  6. 2
      SCADA/Program/DataService/CacheReader.cs
  7. 1
      SCADA/Program/DataService/DataService.csproj
  8. 4
      SCADA/Program/DataService/DeviceAddress.cs
  9. 99
      SCADA/Program/DataService/Enums.cs
  10. 20
      SCADA/Program/DataService/ITag.cs
  11. 275
      SCADA/Program/DataService/PLCGroup.cs
  12. 1
      SCADA/Program/ModbusDriver/ModbusDriver.csproj
  13. 259
      SCADA/Program/ModbusDriver/ModbusRTUDriver.cs
  14. 462
      SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs
  15. 116
      SCADA/Program/ModbusDriver/ModbusTCPDriver.cs
  16. 119
      SCADA/Program/OmronPlcDriver/OmronUdpReader.cs
  17. 97
      SCADA/Program/PanasonicDriver/PanasonicSerialReader.cs
  18. 81
      SCADA/Program/SiemensPLCDriver/SiemensPLCDriver.cs
  19. BIN
      SCADA/dll/DataService.dll
  20. BIN
      SCADA/dll/FileDriver.dll
  21. BIN
      SCADA/dll/ModbusDriver.dll
  22. BIN
      SCADA/dll/OPCDriver.dll
  23. BIN
      SCADA/dll/OmronPlcDriver.dll
  24. BIN
      SCADA/dll/PanasonicDriver.dll
  25. BIN
      SCADA/dll/SiemensPLCDriver.dll

BIN
SCADA/Example/BatchCoreTest.exe

Binary file not shown.

BIN
SCADA/Example/ClientDriver.dll

Binary file not shown.

BIN
SCADA/Example/DataHelper.dll

Binary file not shown.

BIN
SCADA/Example/DataService.dll

Binary file not shown.

63
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
}
}

2
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;
}

1
SCADA/Program/DataService/DataService.csproj

@ -158,6 +158,7 @@
<ItemGroup>
<Compile Include="CacheReader.cs" />
<Compile Include="DeviceAddress.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Eval.cs" />
<Compile Include="TagMetaData.cs" />
<Compile Include="Condition.cs" />

4
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);

99
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
}
}

20
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<T>(object sender, ValueChangingEventArgs<T> e);
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);

275
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<int>();
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<int>();
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<int>();
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;
}
}
}
}
}

1
SCADA/Program/ModbusDriver/ModbusDriver.csproj

@ -104,7 +104,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ModbusRTUDriver.cs" />
<Compile Include="ModbusRTU_TCP.cs" />
<Compile Include="ModbusTCPDriver.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

259
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<int>();
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
{

462
SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs

@ -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<IGroup> _grps = new List<IGroup>(20);
public IEnumerable<IGroup> 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<int> ReadInt32(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 2);
return bit == null ? new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<int>(BitConverter.ToInt32(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<short> ReadInt16(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<short>(BitConverter.ToInt16(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<byte> ReadByte(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<byte>(bit[0], 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<string> ReadString(DeviceAddress address, ushort size)
{
byte[] bit = ReadBytes(address, size);
return bit == null ? new ItemData<string>(string.Empty, 0, QUALITIES.QUALITY_BAD) :
new ItemData<string>(Encoding.ASCII.GetString(bit), 0, QUALITIES.QUALITY_GOOD);
}
public unsafe ItemData<float> ReadFloat(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 2);
return bit == null ? new ItemData<float>(0f, 0, QUALITIES.QUALITY_BAD) :
new ItemData<float>(BitConverter.ToSingle(bit, 0), 0, QUALITIES.QUALITY_GOOD);
//int value = BitConverter.ToInt32(bit, 0);
//return new ItemData<float>(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<bool> ReadBit(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD) :
new ItemData<bool>((bit[0] & (1 << (address.Bit))) > 0, 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<object> ReadValue(DeviceAddress address)
{
return this.ReadValueEx(address);
}
public int WriteBytes(DeviceAddress address, byte[] bit)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteMultipleRegister(address.Start, bit);
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteBit(DeviceAddress address, bool bit)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteSingleCoils(address.Start + address.Bit, bit);
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteBits(DeviceAddress address, byte bits)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteSingleRegister(address.Start, new byte[] { bits });
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteInt16(DeviceAddress address, short value)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteSingleRegister(address.Start, BitConverter.GetBytes(value));
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteInt32(DeviceAddress address, int value)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteMultipleRegister(address.Start, BitConverter.GetBytes(value));
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteFloat(DeviceAddress address, float value)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteMultipleRegister(address.Start, BitConverter.GetBytes(value));
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteString(DeviceAddress address, string str)
{
if (!tcpSynCl.Connected) return -1;
var data = WriteMultipleRegister(address.Start, Encoding.ASCII.GetBytes(str));
tcpSynCl.Send(data, 0, data.Length, SocketFlags.None);//是否存在lock的问题?
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, 0xFF, SocketFlags.None);
return (tcpSynClBuffer[1] & 0x80) > 0 ? -1 : 0;
}
public int WriteValue(DeviceAddress address, object value)
{
return this.WriteValueEx(address, value);
}
public event ShutdownRequestEventHandler OnClose;
public int Limit
{
get { return 60; }
}
public ItemData<Storage>[] ReadMultiple(DeviceAddress[] addrsArr)
{
return this.PLCReadMultiple(new NetShortCacheReader(), addrsArr);
}
public int WriteMultiple(DeviceAddress[] addrArr, object[] buffer)
{
return this.PLCWriteMultiple(new NetShortCacheReader(), addrArr, buffer, Limit);
}
}
}

116
SCADA/Program/ModbusDriver/ModbusTCPDriver.cs

@ -44,6 +44,7 @@ namespace ModbusDriver
dv.Bit = (byte)(st % 16);
st /= 16;
dv.Start = st;
dv.Bit--;
}
break;
case '1':
@ -55,6 +56,7 @@ namespace ModbusDriver
dv.Bit = (byte)(st % 16);
st /= 16;
dv.Start = st;
dv.Bit--;
}
break;
case '4':
@ -69,6 +71,8 @@ namespace ModbusDriver
else
dv.Start = int.Parse(address.Substring(1));
dv.Start--;
dv.Bit--;
dv.ByteOrder = ByteOrder.Network;
}
break;
case '3':
@ -83,6 +87,8 @@ namespace ModbusDriver
else
dv.Start = int.Parse(address.Substring(1));
dv.Start--;
dv.Bit--;
dv.ByteOrder = ByteOrder.Network;
}
break;
}
@ -328,7 +334,7 @@ namespace ModbusDriver
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
ModbusTcpGroup grp = new ModbusTcpGroup(id, name, updateRate, active, this);
NetShortGroup grp = new NetShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
@ -393,11 +399,8 @@ namespace ModbusDriver
internal void CallException(int id, byte function, byte exception)
{
if (tcpSynCl == null) return;
if (exception == Modbus.excExceptionConnectionLost && IsClosed == false)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception)));
}
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception)));
}
public byte[] ReadBytes(DeviceAddress address, ushort size)
@ -503,13 +506,13 @@ namespace ModbusDriver
public int WriteInt16(DeviceAddress address, short value)
{
var data = WriteSingleRegister(address.Area, address.Start, BitConverter.GetBytes(value));
var data = WriteSingleRegister(address.Area, address.Start, BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)));
return data == null ? -1 : 0;
}
public int WriteInt32(DeviceAddress address, int value)
{
var data = WriteMultipleRegister(address.Area, address.Start, BitConverter.GetBytes(value));
var data = WriteMultipleRegister(address.Area, address.Start, BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)));
return data == null ? -1 : 0;
}
@ -547,101 +550,4 @@ namespace ModbusDriver
return this.PLCWriteMultiple(new NetShortCacheReader(), addrArr, buffer, Limit);
}
}
public sealed class ModbusTcpGroup : PLCGroup
{
public ModbusTcpGroup(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<int>();
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 / 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)
{
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;
}
}
}
}
}

119
SCADA/Program/OmronPlcDriver/OmronUdpReader.cs

@ -5,7 +5,6 @@ using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Timers;
namespace OmronPlcDriver
{
@ -23,7 +22,7 @@ namespace OmronPlcDriver
//更新原因:根据现场进行参数调整以提高采集响应速度或者减小网络压力
/***************************************/
/// <summary>
/// PDU的值
/// PDU的值,包大小上限
/// </summary>
int _pdu;
/// <summary>
@ -108,6 +107,7 @@ namespace OmronPlcDriver
}
break;
}
dv.ByteOrder = ByteOrder.Network;
return dv;
}
@ -120,6 +120,7 @@ namespace OmronPlcDriver
private int _timeout;//超时数据
private Socket udpSynCl;
//接受字符串
private byte[] udpSynClBuffer = new byte[1024];
short _id;//驱动id
@ -215,6 +216,7 @@ namespace OmronPlcDriver
public OmronCsCjUDPReader(IDataServer server, short id, string name, string servername, int timeOut = 500, string spare1 = null, string spare2 = null)
{
_id = id;
_name = name;
_server = server;
@ -229,6 +231,7 @@ namespace OmronPlcDriver
_timeout = timeOut;
byte.TryParse(spare1, out _plcNodeId);
byte.TryParse(spare2, out _pcNodeId);
//Console.WriteLine("id->" + _id.ToString() + " name->" + _name + " _server->" + _server + " _ip->" + _ip + " _port->" + _port + " _pdu->" + _pdu + " _timeout->" + _timeout + " plcNodeId->" + _plcNodeId + " pcNodeId->" + PcNodeId);
}
/// <summary>
@ -239,6 +242,8 @@ namespace OmronPlcDriver
{
try
{
Console.WriteLine("开始连接");
if (udpSynCl != null)
udpSynCl.Close();
//IPAddress ip = IPAddress.Parse(_ip);
@ -267,7 +272,7 @@ namespace OmronPlcDriver
/// </summary>
/// <param name="pcnode">电脑节点号,设置和PLC节点不一致即可</param>
/// <param name="startAddress">读取的起始地址</param>
/// <param name="length">读取长度</param>
/// <param name="length">读取长度,2个字节为一个单位</param>
/// <param name="function"></param>
/// <param name="plcnode">PLC节点号,可为0</param>
/// <returns></returns>
@ -373,7 +378,7 @@ namespace OmronPlcDriver
// Read response data
else if (function == 0x1)
{
data = new byte[(write_data[16] * 256 + write_data[17])];
data = new byte[(write_data[16] * 256 + write_data[17]) * 2];
Array.Copy(udpSynClBuffer, 14, data, 0, data.Length);
}
else
@ -429,7 +434,7 @@ namespace OmronPlcDriver
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
OmronCsCjUDPGroup grp = new OmronCsCjUDPGroup(id, name, updateRate, active, this);
NetShortGroup grp = new NetShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
@ -492,18 +497,20 @@ namespace OmronPlcDriver
internal void CallException(int id, byte function, byte exception)
{
if (udpSynCl == null) return;
//Console.WriteLine("OmronReader错误->" + GetErrorString(exception));
if (exception == OmronCSCJ.excExceptionConnectionLost && IsClosed == false)
{
if (OnClose != null)
OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception)));
}
}
/// <summary>
/// 读取字节数组
/// </summary>
/// <param name="address">标签变量地址结构</param>
/// <param name="size">长度</param>
/// <param name="size">长度,</param>
/// <returns></returns>
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
@ -512,7 +519,7 @@ namespace OmronPlcDriver
{
len++;
}
return WriteSyncData(CreateReadHeader(PcNodeId, address.Start, (ushort)(len / 2), (byte)address.DBNumber, (byte)address.Area));
return WriteSyncData(CreateReadHeader(PcNodeId, address.Start, (ushort)(len), (byte)address.DBNumber, (byte)address.Area));
}
/// <summary>
/// 读取32位整数
@ -642,13 +649,13 @@ namespace OmronPlcDriver
public int WriteInt16(DeviceAddress address, short value)
{
var data = WriteSingleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(value), (byte)address.Area);
var data = WriteSingleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), (byte)address.Area);
return data == null ? -1 : 0;
}
public int WriteInt32(DeviceAddress address, int value)
{
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(value), (byte)address.Area);
var data = WriteMultipleRegister(PcNodeId, address.Start, (byte)address.DBNumber, BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), (byte)address.Area);
return data == null ? -1 : 0;
}
@ -687,100 +694,6 @@ namespace OmronPlcDriver
}
}
public sealed class OmronCsCjUDPGroup : PLCGroup
{
public OmronCsCjUDPGroup(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<int>();
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)
{
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)
{
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;
}
}
}
}
/// <summary>
/// 欧姆龙Omron CS/CJ系列PLC数据区功能号和错误代码常数定义类
/// </summary>

97
SCADA/Program/PanasonicDriver/PanasonicSerialReader.cs

@ -94,7 +94,7 @@ namespace PanasonicPLCriver
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0, bool active = false)
{
PanasonicGroup grp = new PanasonicGroup(id, name, updateRate, active, this);
NetShortGroup grp = new NetShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
@ -211,6 +211,7 @@ namespace PanasonicPLCriver
break;
}
}
dv.ByteOrder = ByteOrder.Network;
return dv;
}
#region 实现了四个命令 其余没有做
@ -554,100 +555,6 @@ namespace PanasonicPLCriver
}
#endregion
}
public sealed class PanasonicGroup : PLCGroup
{
public PanasonicGroup(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 System.Timers.Timer();
this._changedList = new List<int>();
this._cacheReader = new NetShortCacheReader();
}
protected override 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)
{
continue;
}
else
{
int len = rcvBytes.Length / 2;
short[] prcv = new short[rcvBytes.Length / 2];
for (int i = 0; i < prcv.Length; i++)
prcv[i] = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(rcvBytes, i * 2));
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)
{
short tt = prcv[iShort1];
short tmp = IPAddress.HostToNetworkOrder((short)(tt ^ cache[iShort]));
DeviceAddress next = addr;
if (tmp != 0)
{
while (addr.Start == next.Start)
{
short ne = (short)(1 << next.Bit);
if ((tmp & (ne)) > 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 struct Panasonic
{

81
SCADA/Program/SiemensPLCDriver/SiemensPLCDriver.cs

@ -719,85 +719,4 @@ namespace SiemensPLCDriver
public event ShutdownRequestEventHandler OnClose;
}
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<int>();
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;
}
}
}
}

BIN
SCADA/dll/DataService.dll

Binary file not shown.

BIN
SCADA/dll/FileDriver.dll

Binary file not shown.

BIN
SCADA/dll/ModbusDriver.dll

Binary file not shown.

BIN
SCADA/dll/OPCDriver.dll

Binary file not shown.

BIN
SCADA/dll/OmronPlcDriver.dll

Binary file not shown.

BIN
SCADA/dll/PanasonicDriver.dll

Binary file not shown.

BIN
SCADA/dll/SiemensPLCDriver.dll

Binary file not shown.
Loading…
Cancel
Save