diff --git a/SCADA/Program/.vs/DataExchange/v15/.suo b/SCADA/Program/.vs/DataExchange/v15/.suo index 7c2a6c4..ff7b3be 100644 Binary files a/SCADA/Program/.vs/DataExchange/v15/.suo and b/SCADA/Program/.vs/DataExchange/v15/.suo differ diff --git a/SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/db.lock b/SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/db.lock new file mode 100644 index 0000000..e69de29 diff --git a/SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/storage.ide b/SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/storage.ide new file mode 100644 index 0000000..5c5f67a Binary files /dev/null and b/SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/storage.ide differ diff --git a/SCADA/Program/.vs/DataExchange/v15/sqlite3/db.lock b/SCADA/Program/.vs/DataExchange/v15/sqlite3/db.lock new file mode 100644 index 0000000..e69de29 diff --git a/SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide b/SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide index d774922..2d5b758 100644 Binary files a/SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide and b/SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide differ diff --git a/SCADA/Program/ABPLCReader/ABPLCDriver.cs b/SCADA/Program/ABPLCReader/ABPLCDriver.cs new file mode 100644 index 0000000..fd558a8 --- /dev/null +++ b/SCADA/Program/ABPLCReader/ABPLCDriver.cs @@ -0,0 +1,518 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; +using System.Timers; +using DataService; +using Tuxeip; + +namespace ABPLCDriver +{ + [Description("EtherNet IP协议")] + public unsafe class ABEtherNetReader : IPLCDriver + { + Eip_Connection* connection; + Eip_Session* session; + byte _rack = 1; + byte _slot; + string _ip; + + short _id; + public short ID + { + get + { + return _id; + } + } + + public bool IsClosed + { + get + { + return connection == null || session == null; + } + } + + public int PDU + { + get + { + return 492; + } + } + + int _timeOut = 1000; + public int TimeOut + { + get + { + return _timeOut; + } + set + { + _timeOut = value; + } + } + + string _name; + public string Name + { + get + { + return _name; + } + } + + public string ServerName + { + get + { + return _ip; + } + set + { + _ip = value; + } + } + + + public byte Rack + { + get + { + return _rack; + } + set + { + _rack = value; + } + } + + public byte Slot + { + get + { + return _slot; + } + set + { + _slot = value; + } + } + + public ABEtherNetReader(IDataServer server, short id, string name) + { + _id = id; + _server = server; + _name = name; + } + + public bool Connect() + { + try + { + if (session != null) Dispose(); + session = Tuxeip_Class.OpenSession(_ip); + byte[] path = new byte[] { _rack, _slot }; + if (session != null) + { + int res = Tuxeip_Class._RegisterSession(session); + connection = Tuxeip_Class.ConnectPLCOverCNET(session, Plc_Type.LGX, path); + } + return (session != null && connection != null); + } + catch (Exception error) + { + if (OnClose != null) + { + OnClose(this, new ShutdownRequestEventArgs(error.Message)); + } + return false; + } + } + + List _groups = new List(); + public IEnumerable Groups + { + get { return _groups; } + } + + IDataServer _server; + public IDataServer Parent + { + get { return _server; } + } + + public IGroup AddGroup(string name, short id, int updateRate, float deadBand, bool active) + { + ABPLCGroup grp = new ABPLCGroup(id, name, updateRate, active, this); + _groups.Add(grp); + return grp; + } + + public bool RemoveGroup(IGroup grp) + { + grp.IsActive = false; + return _groups.Remove(grp); + } + + public event ShutdownRequestEventHandler OnClose; + + public void Dispose() + { + if (connection != null) + Tuxeip_Class._Forward_Close(connection); + if (session != null) + Tuxeip_Class._UnRegisterSession(session); + Tuxeip_Class.CloseSession(session); + Marshal.FreeCoTaskMem((IntPtr)connection); + Marshal.FreeCoTaskMem((IntPtr)session); + connection = null; + session = null; + } + + public string GetAddress(DeviceAddress address) + { + return string.Concat(address.Area == ABAREA.N ? "N" : "F", address.DBNumber.ToString(), "[", address.Start.ToString(), "]", + address.VarType == DataType.BOOL ? "." + address.Bit.ToString() : "");//考虑对localData I/O信号的解析 + } + + public DeviceAddress GetDeviceAddress(string address) + { + DeviceAddress addr = DeviceAddress.Empty;//考虑对localData I/O信号的解析 + if (!string.IsNullOrEmpty(address)) + { + addr.Area = address[0] == 'N' ? ABAREA.N : ABAREA.F; + int index = address.IndexOf('['); + if (index > 0) + { + ushort db; + ushort.TryParse(address.Substring(1, index - 1), out db); + addr.DBNumber = db; + int ind2 = address.IndexOf(']'); + if (ind2 > 0) + { + int start; + int.TryParse(address.Substring(index + 1, ind2 - index - 1), out start); + addr.Start = start; + } + int dig = address.IndexOf('.'); + if (dig > 0) + { + byte bit; + byte.TryParse(address.Substring(dig + 1), out bit); + addr.Bit = bit; + addr.VarType = DataType.BOOL; + } + } + else + { + ushort db; + ushort.TryParse(address.Substring(1), out db); + addr.DBNumber = db; + } + } + return addr; + } + + + public byte[] ReadBytes(DeviceAddress address, ushort size) + { + byte[] result = new byte[size]; + float[] buffer = ReadFloatArray(address, (ushort)(size / 4)); + if (buffer != null) + { + Buffer.BlockCopy(buffer, 0, result, 0, size); + return result; + } + return null; + } + + public float[] ReadFloatArray(DeviceAddress address, ushort size) + { + if (IsClosed) + return null; + else + { + float[] buffer = new float[size]; address.VarType = DataType.FLOAT; var addr = GetAddress(address); + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, addr, size); + if (data != null && data->Varcount > 0) + { + for (int i = 0; i < data->Varcount; i++) + { + buffer[i] = Tuxeip_Class._GetLGXValueAsFloat(data, i); + } + data = null; + return buffer; + } + connection = null; + return null; + } + } + + public ItemData ReadInt32(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData(Tuxeip_Class._GetLGXValueAsInteger(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadInt16(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData((short)Tuxeip_Class._GetLGXValueAsInteger(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadByte(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData((byte)Tuxeip_Class._GetLGXValueAsInteger(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadString(DeviceAddress address, ushort size) + { + if (IsClosed) + return new ItemData(string.Empty, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + byte[] buffer = ReadBytes(address, size); + if (buffer != null) + { + return new ItemData(Encoding.ASCII.GetString(buffer).Trim(), 0, QUALITIES.QUALITY_GOOD); + } + return new ItemData(string.Empty, 0, QUALITIES.QUALITY_BAD); + } + } + + public ItemData ReadFloat(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData(Tuxeip_Class._GetLGXValueAsFloat(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadBit(DeviceAddress address) + { + if (IsClosed) + return new ItemData(false, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData(Tuxeip_Class._GetLGXValueAsInteger(data, 0) > 0, 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadValue(DeviceAddress address) + { + return this.ReadValueEx(address); + } + + public unsafe int WriteBytes(DeviceAddress address, byte[] bit) + { + if (IsClosed) return -1; + fixed (void* b = bit) + { + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_BITARRAY, b, 1); + } + } + + public int WriteBit(DeviceAddress address, bool bit) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_BOOL, &bit, 1); + } + + public int WriteBits(DeviceAddress address, byte bits) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_SINT, &bits, 1); + } + + public int WriteInt16(DeviceAddress address, short value) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_INT, &value, 1); + } + + public int WriteInt32(DeviceAddress address, int value) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_DINT, &value, 1); + } + + public int WriteFloat(DeviceAddress address, float value) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_REAL, &value, 1); + } + + public int WriteString(DeviceAddress address, string str) + { + byte[] b = Encoding.ASCII.GetBytes(str); + return WriteBytes(address, b); + } + + public int WriteValue(DeviceAddress address, object value) + { + return this.WriteValueEx(address, value); + } + + public ItemData ReadUInt32(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData((uint)Tuxeip_Class._GetLGXValueAsInteger(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public ItemData ReadUInt16(DeviceAddress address) + { + if (IsClosed) + return new ItemData(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); + else + { + LGX_Read* data = Tuxeip_Class._ReadLgxData(session, connection, GetAddress(address), 1); + return new ItemData((ushort)Tuxeip_Class._GetLGXValueAsInteger(data, 0), 0, QUALITIES.QUALITY_GOOD); + } + } + + public int WriteUInt16(DeviceAddress address, ushort value) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_INT, &value, 1); + } + + public int WriteUInt32(DeviceAddress address, uint value) + { + if (IsClosed) return -1; + return Tuxeip_Class._WriteLgxData(session, connection, GetAddress(address), LGX_Data_Type.LGX_DINT, &value, 1); + } + + public int Limit + { + get { return 122; } + } + + } + + public sealed class ABPLCGroup : PLCGroup + { + public ABPLCGroup(short id, string name, int updateRate, bool active, ABEtherNetReader plcReader) + { + this._id = id; + this._name = name; + this._updateRate = updateRate; + this._isActive = active; + this._plcReader = plcReader; + this._server = _plcReader.Parent; + this._changedList = new List(); + this._timer = new Timer(); + this._cacheReader = new FloatCacheReader(); + } + + protected override void Poll() + { + float[] cache = (float[])_cacheReader.Cache; + int offset = 0; + foreach (PDUArea area in _rangeList) + { + float[] prcv = ((ABEtherNetReader)_plcReader).ReadFloatArray(area.Start, (ushort)area.Len);//从PLC读取数据 + if (prcv == null) + { + return; + } + else + { + int len = prcv.Length; + int index = area.StartIndex;//index指向_items中的Tag元数据 + int count = index + area.Count; + while (index < count) + { + DeviceAddress addr = _items[index].Address; + int iInt = addr.CacheIndex; + int iInt1 = iInt - offset; + if (addr.VarType == DataType.BOOL) + { + int tmp = (int)prcv[iInt1] ^ (int)cache[iInt]; + 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 <= 4) + { + if (prcv[iInt1] != cache[iInt]) _changedList.Add(index); + } + else + { + int size = addr.DataSize / 4; + for (int i = 0; i < size; i++) + { + if (prcv[iInt1 + i] != cache[iInt + i]) + { + _changedList.Add(index); + break; + } + } + } + index++; + } + } + for (int j = 0; j < len; j++) + { + cache[j + offset] = prcv[j]; + }//将PLC读取的数据写入到CacheReader中 + offset += len; + } + } + } + } + + public class ABAREA + { + public const int N = 0; + public const int F = 1; + public const int I = 2; + public const int O = 3; + } +} diff --git a/SCADA/Program/ABPLCReader/ABPLCDriver.csproj b/SCADA/Program/ABPLCReader/ABPLCDriver.csproj new file mode 100644 index 0000000..ab2de46 --- /dev/null +++ b/SCADA/Program/ABPLCReader/ABPLCDriver.csproj @@ -0,0 +1,126 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F} + Library + Properties + ABPLCReader + ABPLCReader + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + bin\Debug\ABPLCReader.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + bin\x64\Release\ + TRACE + true + true + pdbonly + x64 + bin\Release\ABPLCReader.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + true + bin\Itanium\Debug\ + DEBUG;TRACE + true + full + Itanium + bin\Debug\ABPLCReader.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + bin\Release\ + TRACE + true + true + pdbonly + AnyCPU + bin\Release\ABPLCReader.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + + + + + + + + + + + + + {8965e389-6466-4b30-bd43-83c909044637} + DataService + + + + + \ No newline at end of file diff --git a/SCADA/Program/ABPLCReader/ABPLCDriver.suo b/SCADA/Program/ABPLCReader/ABPLCDriver.suo new file mode 100644 index 0000000..e278b54 Binary files /dev/null and b/SCADA/Program/ABPLCReader/ABPLCDriver.suo differ diff --git a/SCADA/Program/ABPLCReader/Properties/AssemblyInfo.cs b/SCADA/Program/ABPLCReader/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4c6f085 --- /dev/null +++ b/SCADA/Program/ABPLCReader/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ABPLCReader")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ABPLCReader")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dced3a2e-feef-4144-bcad-e2ace205c774")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SCADA/Program/ABPLCReader/Tuxeip_Class.cs b/SCADA/Program/ABPLCReader/Tuxeip_Class.cs new file mode 100644 index 0000000..9637fc9 --- /dev/null +++ b/SCADA/Program/ABPLCReader/Tuxeip_Class.cs @@ -0,0 +1,162 @@ +using System.Runtime.InteropServices; + +namespace Tuxeip +{ + public unsafe class Tuxeip_Class + { + public const int MAX_MSG_LEN = 1024; // a verifier + + public const int EIP_PORT = 0xAF12;//44818 + public const int ENCAP_PROTOCOL = 0x0001; + + /* Ethernet IP commands */ + public const int EIP_NOP = 0x0000; + public const int EIP_LISTTARGETS = 0x0001; // Reserved for legacy RA + public const int EIP_LISTSERVICES = 0x0004; + public const int EIP_LISTIDENTITY = 0x0063; + public const int EIP_LISTINTERFACES = 0x0064; + public const int EIP_REGISTERSESSION = 0x0065; + public const int EIP_UNREGISTERSESSION = 0x0066; + public const int EIP_SENDRRDATA = 0x006F; + public const int EIP_SENDUNITDATA = 0x0070; + public const int EIP_INDICATESTATUS = 0x0072; + public const int EIP_CANCEL = 0x0073; + + // Ethernet IP status code + public const int EIP_SUCCESS = 0x0000; + public const int EIP_INVALID_COMMAND = 0x0001; + public const int EIP_MEMORY = 0x0002; + public const int EIP_INCORRECT_DATA = 0x0003; + public const int EIP_INVALID_SESSION_HANDLE = 0x0064; + public const int EIP_INVALID_LENGTH = 0x0065; + public const int EIP_UNSUPPORTED_PROTOCOL = 0x0069; + + // Ethernet IP Services Class + public const int EIP_SC_COMMUNICATION = 0x0100; + public const int EIP_VERSION = 0x01; + public const int CIP_DEFAULT_TIMEOUT = 1000; + + private const ushort _OriginatorVendorID = 0xFFFE; + private const uint _OriginatorSerialNumber = 0x12345678; + private const byte _Priority = 0x07; + private const sbyte _TimeOut_Ticks = 0x3f; + private const short _Parameters = 0x43f8, _TO_Parameters = 0x43f8; + private const byte _Transport = 0xa3; + private const sbyte _TimeOutMultiplier = 0x01; + + const string PATH = @"tuxeipAB.dll"; + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + private static extern Eip_Session* _OpenSession(string serveur, int port, int buffer_len, int timeout); + public static Eip_Session* OpenSession(string serveur) + { + return _OpenSession(serveur, EIP_PORT, MAX_MSG_LEN, CIP_DEFAULT_TIMEOUT); + } + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern void CloseSession(Eip_Session* session); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _RegisterSession(Eip_Session* session); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _UnRegisterSession(Eip_Session* session); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + private static extern Eip_Connection* _ConnectPLCOverCNET( + Eip_Session* session, + Plc_Type Plc, + byte Priority, + sbyte TimeOut_Ticks, + uint TO_ConnID, //originator's CIP consumed session ID + ushort ConnSerialNumber,// session serial number + ushort OriginatorVendorID, + uint OriginatorSerialNumber, + sbyte TimeOutMultiplier, + uint RPI,// originator to target packet rate in msec + byte Transport, + byte[] path, byte pathsize); + public static Eip_Connection* ConnectPLCOverCNET(Eip_Session* session, Plc_Type Plc, byte[] path) + { + return _ConnectPLCOverCNET(session, Plc, _Priority, _TimeOut_Ticks, 0x12345678, 0x6789, + _OriginatorVendorID, _OriginatorSerialNumber, _TimeOutMultiplier, 5000, _Transport, path, (byte)path.Length); + } + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern Eip_Connection* _ConnectPLCOverDHP( + Eip_Session* session, + Plc_Type Plc, + byte Priority, + sbyte TimeOut_Ticks, + uint TO_ConnID, //originator's CIP consumed session ID + ushort ConnSerialNumber,// session serial number + ushort OriginatorVendorID, + uint OriginatorSerialNumber, + sbyte TimeOutMultiplier, + uint RPI,// originator to target packet rate in msec + byte Transport, + DHP_Channel channel, + byte[] path, byte pathsize); + public static Eip_Connection* ConnectPLCOverDHP(Eip_Session* session, Plc_Type Plc, DHP_Channel channel, byte[] path) + { + return _ConnectPLCOverDHP(session, Plc, _Priority, _TimeOut_Ticks, 0x12345678, 0x6789, + _OriginatorVendorID, _OriginatorSerialNumber, _TimeOutMultiplier, 5000, _Transport, channel, path, (byte)path.Length); + } + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern PLC_Read* _ReadPLCData( + Eip_Session* session, + Eip_Connection* connection, + DHP_Header* dhp, + byte* routepath, byte routepathsize, + Plc_Type type, short tns, + string address, short number); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _WritePLCData( + Eip_Session* session, + Eip_Connection* connection, + DHP_Header* dhp, + byte* routepath, byte routepathsize, + Plc_Type type, short tns, + string address, + PLC_Data_Type datatype, + void* data, + short number); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _PCCC_GetValueAsBoolean(PLC_Read* reply, int index); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern float _PCCC_GetValueAsFloat(PLC_Read* reply, int index); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _PCCC_GetValueAsInteger(PLC_Read* reply, int index); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _GetLGXValueAsInteger(LGX_Read* reply, int index); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern float _GetLGXValueAsFloat(LGX_Read* reply, int index); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _Forward_Close(Eip_Connection* connection); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern LGX_Read* _ReadLgxData( + Eip_Session* session, + Eip_Connection* connection, + string adress, + ushort number); + + [DllImport(PATH, CallingConvention = CallingConvention.Cdecl)] + public static extern int _WriteLgxData( + Eip_Session* session, + Eip_Connection* connection, + string adress, + LGX_Data_Type datatype, + void* data, + //int datasize, + short number); + + } +} diff --git a/SCADA/Program/ABPLCReader/Tuxeip_Struct.cs b/SCADA/Program/ABPLCReader/Tuxeip_Struct.cs new file mode 100644 index 0000000..acf9a82 --- /dev/null +++ b/SCADA/Program/ABPLCReader/Tuxeip_Struct.cs @@ -0,0 +1,115 @@ +using System.Runtime.InteropServices; + +namespace Tuxeip +{ + public enum Plc_Type { Unknow, PLC5, SLC500, LGX } + + public enum DHP_Channel { Channel_A = 0x01, Channel_B } + + public enum Data_Type { UNKNOW, BIT, SINT, TUXINT, DINT, REAL, TIMER, COUNTER } + + public enum PLC_Data_Type + { + PLC_BIT = 1, + PLC_BIT_STRING, + PLC_BYTE_STRING, + PLC_INTEGER, + PLC_TIMER, + PLC_COUNTER, + PLC_CONTROL, + PLC_FLOATING, + PLC_ARRAY, + PLC_ADRESS = 15, + PLC_BCD + } ; + + public enum LGX_Data_Type + { + LGX_BOOL = 0xC1, + LGX_BITARRAY = 0xD3, + LGX_SINT = 0xC2, + LGX_INT = 0xC3, + LGX_DINT = 0xC4, + LGX_REAL = 0xCA + } + + + + [StructLayout(LayoutKind.Explicit)] + public unsafe struct Eip_Session + { + [FieldOffset(0)] + int sock; + [FieldOffset(4)] + uint Session_Handle; + [FieldOffset(8)] + uint Sender_ContextL; + [FieldOffset(12)] + uint Sender_ContextH; + [FieldOffset(16)] + int timeout; + [FieldOffset(20)] + int References; + [FieldOffset(24)] + void* Data; + } + + [StructLayout(LayoutKind.Explicit)] + public unsafe struct Eip_Connection + { + /* Connected send parameters */ + [FieldOffset(0)] + Eip_Session* Session; + [FieldOffset(4)] + int References; + [FieldOffset(8)] + void* Data; + [FieldOffset(12)] + ushort ConnectionSerialNumber; + [FieldOffset(14)] + ushort OriginatorVendorID; + [FieldOffset(16)] + uint OriginatorSerialNumber; + + [FieldOffset(20)] + uint OT_ConnID; //originator's CIP Produced session ID + + [FieldOffset(24)] + uint TO_ConnID; //originator's CIP consumed session ID + [FieldOffset(28)] + short packet; + [FieldOffset(30)] + byte Path_size;// + //BYTE Path[0]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct PLC_Read + { + public PLC_Data_Type type; + public int Varcount; + public int totalsize; + public int elementsize; + public uint mask; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct DHP_Header + { + public ushort Dest_link; + public ushort Dest_adress; + public ushort Src_link; + public ushort Src_adress; + //BYTE data; // the PCCC request + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct LGX_Read + { + public LGX_Data_Type type; + public int Varcount; + public int totalsize; + public int elementsize; + public uint mask; + } +} diff --git a/SCADA/Program/DataExchange.sln b/SCADA/Program/DataExchange.sln index 3a0ccad..8caf0ec 100644 --- a/SCADA/Program/DataExchange.sln +++ b/SCADA/Program/DataExchange.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2020 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OPCDriver", "OPCDriver\OPCDriver.csproj", "{054DB7AC-EB2C-439F-80D4-63E823B279C8}" EndProject @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PanasonicDriver", "Panasoni EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmronPlcDriver", "OmronPlcDriver\OmronPlcDriver.csproj", "{BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ABPLCDriver", "ABPLCReader\ABPLCDriver.csproj", "{02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -321,8 +323,31 @@ Global {BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x64.Build.0 = Release|Any CPU {BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x86.ActiveCfg = Release|Any CPU {BAF8082B-8DD8-4E7C-9C5B-D9213E08C3B1}.Release|x86.Build.0 = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Itanium.ActiveCfg = Debug|Itanium + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Itanium.Build.0 = Debug|Itanium + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|x64.ActiveCfg = Debug|x64 + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|x64.Build.0 = Debug|x64 + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|x86.ActiveCfg = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Debug|x86.Build.0 = Debug|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Any CPU.Build.0 = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Itanium.ActiveCfg = Release|Itanium + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Itanium.Build.0 = Release|Itanium + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x64.ActiveCfg = Release|x64 + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x64.Build.0 = Release|x64 + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x86.ActiveCfg = Release|Any CPU + {02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C86B1B4B-CEC2-468B-B6F3-AE7797EED1D6} + EndGlobalSection EndGlobal diff --git a/SCADA/Program/DataService/CacheReader.cs b/SCADA/Program/DataService/CacheReader.cs index 6ce7370..84e8834 100644 --- a/SCADA/Program/DataService/CacheReader.cs +++ b/SCADA/Program/DataService/CacheReader.cs @@ -933,7 +933,7 @@ namespace DataService public int GetOffset(DeviceAddress start, DeviceAddress end) { - return start.Area == end.Area && start.DBNumber == end.DBNumber ? start.Start - end.Start : ushort.MaxValue; + return start.Area == end.Area && start.DBNumber == end.DBNumber ? start.Start - end.Start : int.MaxValue; } public unsafe ItemData ReadBit(DeviceAddress address) diff --git a/SCADA/dll/ABPLCReader.dll b/SCADA/dll/ABPLCReader.dll new file mode 100644 index 0000000..4402a20 Binary files /dev/null and b/SCADA/dll/ABPLCReader.dll differ diff --git a/SCADA/dll/DataService.dll b/SCADA/dll/DataService.dll index b5cec48..238fd86 100644 Binary files a/SCADA/dll/DataService.dll and b/SCADA/dll/DataService.dll differ diff --git a/SCADA/dll/Tuxeip.dll b/SCADA/dll/Tuxeip.dll new file mode 100644 index 0000000..93d01a9 Binary files /dev/null and b/SCADA/dll/Tuxeip.dll differ