Browse Source

update cacheReader

pull/15/head
Gavin 9 years ago
parent
commit
c0706e7f03
  1. 63
      SCADA/Program/DataService/Alarm.cs
  2. 4
      SCADA/Program/DataService/CacheReader.cs
  3. 1
      SCADA/Program/DataService/DataService.csproj
  4. 4
      SCADA/Program/DataService/DeviceAddress.cs
  5. 99
      SCADA/Program/DataService/Enums.cs
  6. 20
      SCADA/Program/DataService/ITag.cs
  7. 275
      SCADA/Program/DataService/PLCGroup.cs
  8. 1
      SCADA/Program/ModbusDriver/ModbusDriver.csproj
  9. 28
      SCADA/Program/ModbusDriver/ModbusRTUDriver.cs
  10. 462
      SCADA/Program/ModbusDriver/ModbusRTU_TCP.cs
  11. 112
      SCADA/Program/ModbusDriver/ModbusTCPDriver.cs
  12. 103
      SCADA/Program/OmronPlcDriver/OmronUdpReader.cs
  13. 97
      SCADA/Program/PanasonicDriver/PanasonicSerialReader.cs
  14. 81
      SCADA/Program/SiemensPLCDriver/SiemensPLCDriver.cs
  15. BIN
      SCADA/dll/DataService.dll
  16. BIN
      SCADA/dll/ModbusDriver.dll
  17. BIN
      SCADA/dll/OmronPlcDriver.dll
  18. BIN
      SCADA/dll/PanasonicDriver.dll
  19. BIN
      SCADA/dll/SiemensPLCDriver.dll

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

4
SCADA/Program/DataService/CacheReader.cs

@ -503,7 +503,7 @@ namespace DataService
public unsafe ItemData<bool> ReadBit(DeviceAddress address)
{
return new ItemData<bool>((_cache[address.CacheIndex] & (1 << address.Bit.BitSwap())) != 0, 0, QUALITIES.QUALITY_GOOD);
return new ItemData<bool>((_cache[address.CacheIndex] & (1 << address.Bit)) != 0, 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<short> ReadInt16(DeviceAddress address)
@ -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>

28
SCADA/Program/ModbusDriver/ModbusRTUDriver.cs

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

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

112
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)
@ -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.BitSwap())) > 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;
}
}
}
}
}

103
SCADA/Program/OmronPlcDriver/OmronUdpReader.cs

@ -108,6 +108,7 @@ namespace OmronPlcDriver
}
break;
}
dv.ByteOrder = ByteOrder.Network;
return dv;
}
@ -434,7 +435,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;
}
@ -694,106 +695,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()
{
//Console.WriteLine("开始遍历》》");
short[] cache = (short[])_cacheReader.Cache;
int offset = 0;
foreach (PDUArea area in _rangeList)
{
//Console.WriteLine(">>读取:" + area.Start.DBNumber.ToString() + "@" + DateTime.Now.ToString());
byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
if (rcvBytes == null || rcvBytes.Length == 0)
{
//Console.WriteLine(">>结果:" + area.Start.DBNumber.ToString() + "->失败");
continue;
}
else
{
//Console.WriteLine(">>结果:" + area.Start.DBNumber.ToString() + "->" + BitConverter.ToString(rcvBytes) + " at" + DateTime.Now.ToString());
int len = area.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.BitSwap()) > 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/ModbusDriver.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