From aff5df1b3335ec4ab6ef3be39b74fbbbe60901be Mon Sep 17 00:00:00 2001 From: Michele Cattafesta Date: Sat, 9 Jul 2016 00:08:32 +0200 Subject: [PATCH] S7.Net and S7.Net.Core unification (issue #56): moved files, updated csproj, minor modification for compatibility in SocketClient class. Signed-off-by: Michele Cattafesta --- S7.Net.Core/PLC.cs | 1109 -------------------------------- S7.Net.Core/S7.Net.Core.csproj | 57 +- S7.Net.Core/SocketClient.cs | 54 +- S7.Net/Conversion.cs | 235 +++++++ S7.Net/Enums.cs | 51 ++ S7.Net/PLC.cs | 53 +- S7.Net/S7.Net.csproj | 67 +- S7.Net/Types/Boolean.cs | 26 + S7.Net/Types/Byte.cs | 20 + S7.Net/Types/ByteArray.cs | 44 ++ S7.Net/Types/Class.cs | 234 +++++++ S7.Net/Types/Counter.cs | 61 ++ S7.Net/Types/DInt.cs | 71 ++ S7.Net/Types/DWord.cs | 59 ++ S7.Net/Types/DataItem.cs | 18 + S7.Net/Types/Double.cs | 166 +++++ S7.Net/Types/Int.cs | 74 +++ S7.Net/Types/String.cs | 34 + S7.Net/Types/Struct.cs | 237 +++++++ S7.Net/Types/Timer.cs | 74 +++ S7.Net/Types/Word.cs | 61 ++ 21 files changed, 1622 insertions(+), 1183 deletions(-) delete mode 100644 S7.Net.Core/PLC.cs create mode 100644 S7.Net/Conversion.cs create mode 100644 S7.Net/Enums.cs create mode 100644 S7.Net/Types/Boolean.cs create mode 100644 S7.Net/Types/Byte.cs create mode 100644 S7.Net/Types/ByteArray.cs create mode 100644 S7.Net/Types/Class.cs create mode 100644 S7.Net/Types/Counter.cs create mode 100644 S7.Net/Types/DInt.cs create mode 100644 S7.Net/Types/DWord.cs create mode 100644 S7.Net/Types/DataItem.cs create mode 100644 S7.Net/Types/Double.cs create mode 100644 S7.Net/Types/Int.cs create mode 100644 S7.Net/Types/String.cs create mode 100644 S7.Net/Types/Struct.cs create mode 100644 S7.Net/Types/Timer.cs create mode 100644 S7.Net/Types/Word.cs diff --git a/S7.Net.Core/PLC.cs b/S7.Net.Core/PLC.cs deleted file mode 100644 index 2d77a53..0000000 --- a/S7.Net.Core/PLC.cs +++ /dev/null @@ -1,1109 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using S7.Net.Types; -using Double = System.Double; - -namespace S7.Net -{ - public class Plc : IDisposable - { - private SocketClient _mSocket; //TCP connection to device - - /// - /// Ip address of the plc - /// - public string IP { get; private set; } - - /// - /// Cpu type of the plc - /// - public CpuType CPU { get; private set; } - - /// - /// Rack of the plc - /// - public Int16 Rack { get; private set; } - - /// - /// Slot of the CPU of the plc - /// - public Int16 Slot { get; private set; } - - /// - /// Pings the IP address and returns true if the result of the ping is Success. - /// - public bool IsAvailable - { - get - { - //using (Ping ping = new Ping()) - //{ - //PingReply result; - //try - //{ - // result = ping.Send(IP); - //} - //catch (PingException) - //{ - // result = null; - //} - return (!string.IsNullOrWhiteSpace(IP)); // result != null && result.Status == IPStatus.Success; - //} - } - } - - /// - /// Checks if the socket is connected and polls the other peer (the plc) to see if it's connected. - /// This is the variable that you should continously check to see if the communication is working - /// See also: http://stackoverflow.com/questions/2661764/how-to-check-if-a-socket-is-connected-disconnected-in-c - /// - public bool IsConnected - { - get - { - try - { - if (_mSocket == null) - return false; - return _mSocket.Connected; //!((_mSocket.Poll(1000, SelectMode.SelectRead) && (_mSocket.Available == 0)) || !_mSocket.Connected); - } - catch { return false; } - } - } - - /// - /// Contains the last error registered when executing a function - /// - public string LastErrorString { get; private set; } - - /// - /// Contains the last error code registered when executing a function - /// - public ErrorCode LastErrorCode { get; private set; } - - /// - /// Creates a PLC object with all the parameters needed for connections. - /// For S7-1200 and S7-1500, the default is rack = 0 and slot = 0. - /// You need slot > 0 if you are connecting to external ethernet card (CP). - /// For S7-300 and S7-400 the default is rack = 0 and slot = 2. - /// - /// CpuType of the plc (select from the enum) - /// Ip address of the plc - /// rack of the plc, usually it's 0, but check in the hardware configuration of Step7 or TIA portal - /// slot of the CPU of the plc, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500. - /// If you use an external ethernet card, this must be set accordingly. - public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot) - { - IP = ip; - CPU = cpu; - Rack = rack; - Slot = slot; - } - - /// - /// Open a socket and connects to the plc, sending all the corrected package and returning if the connection was successful (ErroreCode.NoError) of it was wrong. - /// - /// Returns ErrorCode.NoError if the connection was successful, otherwise check the ErrorCode - public ErrorCode Open() - { - byte[] bReceive = new byte[256]; - - try - { - // check if available - if (!IsAvailable) - { - throw new Exception(); - } - } - catch - { - LastErrorCode = ErrorCode.IPAddressNotAvailable; - LastErrorString = string.Format("Destination IP-Address '{0}' is not available!", IP); - return LastErrorCode; - } - - try - { - // open the channel - _mSocket = new SocketClient(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - - _mSocket.SetReceiveTimeout(1000); - _mSocket.SetSendTimeout(1000); - - IPEndPoint server = new IPEndPoint(IPAddress.Parse(IP), 102); - _mSocket.Connect(server); - } - catch (Exception ex) - { - LastErrorCode = ErrorCode.ConnectionError; - LastErrorString = ex.Message; - return ErrorCode.ConnectionError; - } - - try - { - byte[] bSend1 = { 3, 0, 0, 22, 17, 224, 0, 0, 0, 46, 0, 193, 2, 1, 0, 194, 2, 3, 0, 192, 1, 9 }; - - switch (CPU) - { - case CpuType.S7200: - //S7200: Chr(193) & Chr(2) & Chr(16) & Chr(0) 'Eigener Tsap - bSend1[11] = 193; - bSend1[12] = 2; - bSend1[13] = 16; - bSend1[14] = 0; - //S7200: Chr(194) & Chr(2) & Chr(16) & Chr(0) 'Fremder Tsap - bSend1[15] = 194; - bSend1[16] = 2; - bSend1[17] = 16; - bSend1[18] = 0; - break; - case CpuType.S71200: - case CpuType.S7300: - //S7300: Chr(193) & Chr(2) & Chr(1) & Chr(0) 'Eigener Tsap - bSend1[11] = 193; - bSend1[12] = 2; - bSend1[13] = 1; - bSend1[14] = 0; - //S7300: Chr(194) & Chr(2) & Chr(3) & Chr(2) 'Fremder Tsap - bSend1[15] = 194; - bSend1[16] = 2; - bSend1[17] = 3; - bSend1[18] = (byte)(Rack * 2 * 16 + Slot); - break; - case CpuType.S7400: - //S7400: Chr(193) & Chr(2) & Chr(1) & Chr(0) 'Eigener Tsap - bSend1[11] = 193; - bSend1[12] = 2; - bSend1[13] = 1; - bSend1[14] = 0; - //S7400: Chr(194) & Chr(2) & Chr(3) & Chr(3) 'Fremder Tsap - bSend1[15] = 194; - bSend1[16] = 2; - bSend1[17] = 3; - bSend1[18] = (byte)(Rack * 2 * 16 + Slot); - break; - case CpuType.S71500: - // Eigener Tsap - bSend1[11] = 193; - bSend1[12] = 2; - bSend1[13] = 0x10; - bSend1[14] = 0x2; - // Fredmer Tsap - bSend1[15] = 194; - bSend1[16] = 2; - bSend1[17] = 0x3; - bSend1[18] = (byte)(Rack * 2 * 16 + Slot); - break; - default: - return ErrorCode.WrongCPU_Type; - } - - _mSocket.Send(bSend1, 22); - if (_mSocket.Receive(bReceive, 22) != 22) - { - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - } - - byte[] bsend2 = { 3, 0, 0, 25, 2, 240, 128, 50, 1, 0, 0, 255, 255, 0, 8, 0, 0, 240, 0, 0, 3, 0, 3, 1, 0 }; - _mSocket.Send(bsend2, 25); - - if (_mSocket.Receive(bReceive, 27) != 27) - { - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - } - } - catch - { - LastErrorCode = ErrorCode.ConnectionError; - LastErrorString = string.Format("Couldn't establish the connection to {0}!", IP); - return ErrorCode.ConnectionError; - } - - return ErrorCode.NoError; - } - - /// - /// Disonnects from the plc and close the socket - /// - public void Close() - { - if (_mSocket != null && _mSocket.Connected) - { - _mSocket.Close(); - } - } - - /// - /// Reads multiple vars in a single request. - /// You have to create and pass a list of DataItems and you obtain in response the same list with the values. - /// Values are stored in the property "Value" of the dataItem and are already converted. - /// If you don't want the conversion, just create a dataItem of bytes. - /// DataItems must not be more than 20 (protocol restriction) and bytes must not be more than 200 + 22 of header (protocol restriction). - /// - /// List of dataitems that contains the list of variables that must be read. Maximum 20 dataitems are accepted. - public void ReadMultipleVars(List dataItems) - { - int cntBytes = dataItems.Sum(dataItem => VarTypeToByteLength(dataItem.VarType, dataItem.Count)); - - if (dataItems.Count > 20) throw new Exception("Too many vars requested"); - if (cntBytes > 222) throw new Exception("Too many bytes requested"); //todo, proper TDU check + split in multiple requests - - try - { - // first create the header - int packageSize = 19 + (dataItems.Count * 12); - Types.ByteArray package = new ByteArray(packageSize); - package.Add(ReadHeaderPackage(dataItems.Count)); - // package.Add(0x02); // datenart - foreach (var dataItem in dataItems) - { - package.Add(CreateReadDataRequestPackage(dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count))); - } - - _mSocket.Send(package.array, package.array.Length); - - byte[] bReceive = new byte[512]; - int numReceived = _mSocket.Receive(bReceive, 512); - if (bReceive[21] != 0xff) throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - - int offset = 25; - foreach (var dataItem in dataItems) - { - int byteCnt = VarTypeToByteLength(dataItem.VarType, dataItem.Count); - byte[] bytes = new byte[byteCnt]; - - for (int i = 0; i < byteCnt; i++) - { - bytes[i] = bReceive[i + offset]; - } - - offset += byteCnt + 4; - - dataItem.Value = ParseBytes(dataItem.VarType, bytes, dataItem.Count); - } - } - catch (SocketException socketException) - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = socketException.Message; - } - catch (Exception exc) - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - } - } - - /// - /// Reads up to 200 bytes from the plc and returns an array of bytes. You must specify the memory area type, memory are address, byte start address and bytes count. - /// If the read was not successful, check LastErrorCode or LastErrorString. - /// - /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Byte count, if you want to read 120 bytes, set this to 120. This parameter can't be higher than 200. If you need more, use recursion. - /// Returns the bytes in an array - public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count) - { - byte[] bytes = new byte[count]; - - try - { - // first create the header - int packageSize = 31; - Types.ByteArray package = new ByteArray(packageSize); - package.Add(ReadHeaderPackage()); - // package.Add(0x02); // datenart - package.Add(CreateReadDataRequestPackage(dataType, db, startByteAdr, count)); - - _mSocket.Send(package.array, package.array.Length); - - byte[] bReceive = new byte[512]; - int numReceived = _mSocket.Receive(bReceive, 512); - if (bReceive[21] != 0xff) throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - - for (int cnt = 0; cnt < count; cnt++) - bytes[cnt] = bReceive[cnt + 25]; - - return bytes; - } - catch (SocketException socketException) - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = socketException.Message; - return null; - } - catch (Exception exc) - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = exc.Message; - return null; - } - } - - /// - /// Given a S7 variable type (Bool, Word, DWord, etc.), it returns how many bytes to read. - /// - /// - /// - /// - public int VarTypeToByteLength(VarType varType, int varCount = 1) - { - switch (varType) - { - case VarType.Bit: - return varCount; //TODO - case VarType.Byte: - return (varCount < 1) ? 1 : varCount; - case VarType.String: - return varCount; - case VarType.Word: - case VarType.Timer: - case VarType.Int: - case VarType.Counter: - return varCount * 2; - case VarType.DWord: - case VarType.DInt: - case VarType.Real: - return varCount * 4; - default: - return 0; - } - } - - /// - /// Given a S7 variable type (Bool, Word, DWord, etc.), it converts the bytes in the appropriate C# format. - /// - /// - /// - /// - /// - public object ParseBytes(VarType varType, byte[] bytes, int varCount) - { - if (bytes == null) return null; - - switch (varType) - { - case VarType.Byte: - if (varCount == 1) - return bytes[0]; - else - return bytes; - case VarType.Word: - if (varCount == 1) - return Types.Word.FromByteArray(bytes); - else - return Types.Word.ToArray(bytes); - case VarType.Int: - if (varCount == 1) - return Types.Int.FromByteArray(bytes); - else - return Types.Int.ToArray(bytes); - case VarType.DWord: - if (varCount == 1) - return Types.DWord.FromByteArray(bytes); - else - return Types.DWord.ToArray(bytes); - case VarType.DInt: - if (varCount == 1) - return Types.DInt.FromByteArray(bytes); - else - return Types.DInt.ToArray(bytes); - case VarType.Real: - if (varCount == 1) - return Types.Double.FromByteArray(bytes); - else - return Types.Double.ToArray(bytes); - case VarType.String: - return Types.String.FromByteArray(bytes); - case VarType.Timer: - if (varCount == 1) - return Types.Timer.FromByteArray(bytes); - else - return Types.Timer.ToArray(bytes); - case VarType.Counter: - if (varCount == 1) - return Types.Counter.FromByteArray(bytes); - else - return Types.Counter.ToArray(bytes); - case VarType.Bit: - return null; //TODO - default: - return null; - } - } - - /// - /// Read and decode a certain number of bytes of the "VarType" provided. - /// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc). - /// If the read was not successful, check LastErrorCode or LastErrorString. - /// - /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Type of the variable/s that you are reading - /// Number of - public object Read(DataType dataType, int db, int startByteAdr, VarType varType, int varCount) - { - int cntBytes = VarTypeToByteLength(varType, varCount); - byte[] bytes = ReadBytes(dataType, db, startByteAdr, cntBytes); - - return ParseBytes(varType, bytes, varCount); - } - - /// - /// Reads a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. - /// If the read was not successful, check LastErrorCode or LastErrorString. - /// - /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. - /// Returns an object that contains the value. This object must be cast accordingly. - public object Read(string variable) - { - DataType mDataType; - int mDB; - int mByte; - int mBit; - - byte objByte; - UInt16 objUInt16; - UInt32 objUInt32; - double objDouble; - BitArray objBoolArray; - - string txt = variable.ToUpper(); - txt = txt.Replace(" ", ""); // remove spaces - - try - { - switch (txt.Substring(0, 2)) - { - case "DB": - string[] strings = txt.Split(new char[] { '.' }); - if (strings.Length < 2) - throw new Exception(); - - mDB = int.Parse(strings[0].Substring(2)); - string dbType = strings[1].Substring(0, 3); - int dbIndex = int.Parse(strings[1].Substring(3)); - - switch (dbType) - { - case "DBB": - byte obj = (byte)Read(DataType.DataBlock, mDB, dbIndex, VarType.Byte, 1); - return obj; - case "DBW": - UInt16 objI = (UInt16)Read(DataType.DataBlock, mDB, dbIndex, VarType.Word, 1); - return objI; - case "DBD": - UInt32 objU = (UInt32)Read(DataType.DataBlock, mDB, dbIndex, VarType.DWord, 1); - return objU; - case "DBX": - mByte = dbIndex; - mBit = int.Parse(strings[2]); - if (mBit > 7) throw new Exception(); - byte obj2 = (byte)Read(DataType.DataBlock, mDB, mByte, VarType.Byte, 1); - objBoolArray = new BitArray(new byte[] { obj2 }); - return objBoolArray[mBit]; - default: - throw new Exception(); - } - case "EB": - // Input byte - objByte = (byte)Read(DataType.Input, 0, int.Parse(txt.Substring(2)), VarType.Byte, 1); - return objByte; - case "EW": - // Input word - objUInt16 = (UInt16)Read(DataType.Input, 0, int.Parse(txt.Substring(2)), VarType.Word, 1); - return objUInt16; - case "ED": - // Input double-word - objUInt32 = (UInt32)Read(DataType.Input, 0, int.Parse(txt.Substring(2)), VarType.DWord, 1); - return objUInt32; - case "AB": - // Output byte - objByte = (byte)Read(DataType.Output, 0, int.Parse(txt.Substring(2)), VarType.Byte, 1); - return objByte; - case "AW": - // Output word - objUInt16 = (UInt16)Read(DataType.Output, 0, int.Parse(txt.Substring(2)), VarType.Word, 1); - return objUInt16; - case "AD": - // Output double-word - objUInt32 = (UInt32)Read(DataType.Output, 0, int.Parse(txt.Substring(2)), VarType.DWord, 1); - return objUInt32; - case "MB": - // Memory byte - objByte = (byte)Read(DataType.Memory, 0, int.Parse(txt.Substring(2)), VarType.Byte, 1); - return objByte; - case "MW": - // Memory word - objUInt16 = (UInt16)Read(DataType.Memory, 0, int.Parse(txt.Substring(2)), VarType.Word, 1); - return objUInt16; - case "MD": - // Memory double-word - objUInt32 = (UInt32)Read(DataType.Memory, 0, int.Parse(txt.Substring(2)), VarType.DWord, 1); - return objUInt32; - default: - switch (txt.Substring(0, 1)) - { - case "E": - case "I": - // Input - mDataType = DataType.Input; - break; - case "A": - case "O": - // Output - mDataType = DataType.Output; - break; - case "M": - // Memory - mDataType = DataType.Memory; - break; - case "T": - // Timer - objDouble = (double)Read(DataType.Timer, 0, int.Parse(txt.Substring(1)), VarType.Timer, 1); - return objDouble; - case "Z": - case "C": - // Counter - objUInt16 = (UInt16)Read(DataType.Counter, 0, int.Parse(txt.Substring(1)), VarType.Counter, 1); - return objUInt16; - default: - throw new Exception(); - } - - string txt2 = txt.Substring(1); - if (txt2.IndexOf(".") == -1) throw new Exception(); - - mByte = int.Parse(txt2.Substring(0, txt2.IndexOf("."))); - mBit = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1)); - if (mBit > 7) throw new Exception(); - var obj3 = (byte)Read(mDataType, 0, mByte, VarType.Byte, 1); - objBoolArray = new BitArray(new byte[] { obj3 }); - return objBoolArray[mBit]; - } - } - catch - { - LastErrorCode = ErrorCode.WrongVarFormat; - LastErrorString = "The variable'" + variable + "' could not be read. Please check the syntax and try again."; - return LastErrorCode; - } - } - - /// - /// Reads all the bytes needed to fill a struct in C#, starting from a certain address, and return an object that can be casted to the struct. - /// - /// Type of the struct to be readed (es.: TypeOf(MyStruct)). - /// Address of the DB. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Returns a struct that must be cast. - public object ReadStruct(Type structType, int db, int startByteAdr = 0) - { - int numBytes = Types.Struct.GetStructSize(structType); - // now read the package - List resultBytes = ReadMultipleBytes(numBytes, db, startByteAdr); - - // and decode it - return Types.Struct.FromBytes(structType, resultBytes.ToArray()); - } - - /// - /// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the plc. - /// This reads ony properties, it doesn't read private variable or public variable without {get;set;} specified. - /// - /// Instance of the class that will store the values - /// Index of the DB; es.: 1 is for DB1 - /// Start byte address. If you want to read DB1.DBW200, this is 200. - public void ReadClass(object sourceClass, int db, int startByteAdr = 0) - { - Type classType = sourceClass.GetType(); - int numBytes = Types.Class.GetClassSize(classType); - // now read the package - List resultBytes = ReadMultipleBytes(numBytes, db, startByteAdr); - // and decode it - Types.Class.FromBytes(sourceClass, classType, resultBytes.ToArray()); - } - - - /// - /// Writes up to 200 bytes to the plc and returns NoError if successful. You must specify the memory area type, memory are address, byte start address and bytes count. - /// If the read was not successful, check LastErrorCode or LastErrorString. - /// - /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. - /// NoError if it was successful, or the error is specified - public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value) - { - byte[] bReceive = new byte[513]; - int varCount = 0; - - try - { - varCount = value.Length; - // first create the header - int packageSize = 35 + value.Length; - Types.ByteArray package = new Types.ByteArray(packageSize); - - package.Add(new byte[] { 3, 0, 0 }); - package.Add((byte)packageSize); - package.Add(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 }); - package.Add(Types.Word.ToByteArray((ushort)(varCount - 1))); - package.Add(new byte[] { 0, 0x0e }); - package.Add(Types.Word.ToByteArray((ushort)(varCount + 4))); - package.Add(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 }); - package.Add(Types.Word.ToByteArray((ushort)varCount)); - package.Add(Types.Word.ToByteArray((ushort)(db))); - package.Add((byte)dataType); - var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191 - package.Add((byte)overflow); - package.Add(Types.Word.ToByteArray((ushort)(startByteAdr * 8))); - package.Add(new byte[] { 0, 4 }); - package.Add(Types.Word.ToByteArray((ushort)(varCount * 8))); - - // now join the header and the data - package.Add(value); - - _mSocket.Send(package.array, package.array.Length); - - int numReceived = _mSocket.Receive(bReceive, 512); - if (bReceive[21] != 0xff) - { - throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); - } - - return ErrorCode.NoError; - } - catch - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = ""; - return LastErrorCode; - } - } - - /// - /// Takes in input an object and tries to parse it to an array of values. This can be used to write many data, all of the same type. - /// You must specify the memory area type, memory are address, byte start address and bytes count. - /// If the read was not successful, check LastErrorCode or LastErrorString. - /// - /// Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output. - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion. - /// NoError if it was successful, or the error is specified - public ErrorCode Write(DataType dataType, int db, int startByteAdr, object value) - { - byte[] package = null; - - switch (value.GetType().Name) - { - case "Byte": - package = Types.Byte.ToByteArray((byte)value); - break; - case "Int16": - package = Types.Int.ToByteArray((Int16)value); - break; - case "UInt16": - package = Types.Word.ToByteArray((UInt16)value); - break; - case "Int32": - package = Types.DInt.ToByteArray((Int32)value); - break; - case "UInt32": - package = Types.DWord.ToByteArray((UInt32)value); - break; - case "Double": - package = Types.Double.ToByteArray((Double)value); - break; - case "Byte[]": - package = (byte[])value; - break; - case "Int16[]": - package = Types.Int.ToByteArray((Int16[])value); - break; - case "UInt16[]": - package = Types.Word.ToByteArray((UInt16[])value); - break; - case "Int32[]": - package = Types.DInt.ToByteArray((Int32[])value); - break; - case "UInt32[]": - package = Types.DWord.ToByteArray((UInt32[])value); - break; - case "Double[]": - package = Types.Double.ToByteArray((double[])value); - break; - case "String": - package = Types.String.ToByteArray(value as string); - break; - default: - return ErrorCode.WrongVarFormat; - } - return WriteBytes(dataType, db, startByteAdr, package); - } - - /// - /// Writes a single variable from the plc, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. - /// If the write was not successful, check LastErrorCode or LastErrorString. - /// - /// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc. - /// Value to be written to the plc - /// NoError if it was successful, or the error is specified - public ErrorCode Write(string variable, object value) - { - DataType mDataType; - int mDB; - int mByte; - int mBit; - - string addressLocation; - byte _byte; - object objValue; - - string txt = variable.ToUpper(); - txt = txt.Replace(" ", ""); // Remove spaces - - try - { - switch (txt.Substring(0, 2)) - { - case "DB": - string[] strings = txt.Split(new char[] { '.' }); - if (strings.Length < 2) - throw new Exception(); - - mDB = int.Parse(strings[0].Substring(2)); - string dbType = strings[1].Substring(0, 3); - int dbIndex = int.Parse(strings[1].Substring(3)); - - switch (dbType) - { - case "DBB": - objValue = Convert.ChangeType(value, typeof(byte)); - return Write(DataType.DataBlock, mDB, dbIndex, (byte)objValue); - case "DBW": - if (value is short) - { - objValue = ((short)value).ConvertToUshort(); - } - else - { - objValue = Convert.ChangeType(value, typeof(UInt16)); - } - return Write(DataType.DataBlock, mDB, dbIndex, (UInt16)objValue); - case "DBD": - if (value is int) - { - return Write(DataType.DataBlock, mDB, dbIndex, (Int32)value); - } - else - { - objValue = Convert.ChangeType(value, typeof(UInt32)); - } - return Write(DataType.DataBlock, mDB, dbIndex, (UInt32)objValue); - case "DBX": - mByte = dbIndex; - mBit = int.Parse(strings[2]); - if (mBit > 7) - { - throw new Exception(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", mBit)); - } - byte b = (byte)Read(DataType.DataBlock, mDB, mByte, VarType.Byte, 1); - if (Convert.ToInt32(value) == 1) - b = (byte)(b | (byte)Math.Pow(2, mBit)); // Bit setzen - else - b = (byte)(b & (b ^ (byte)Math.Pow(2, mBit))); // Bit rücksetzen - - return Write(DataType.DataBlock, mDB, mByte, (byte)b); - case "DBS": - // DB-String - return Write(DataType.DataBlock, mDB, dbIndex, (string)value); - default: - throw new Exception(string.Format("Addressing Error: Unable to parse address {0}. Supported formats include DBB (byte), DBW (word), DBD (dword), DBX (bitwise), DBS (string).", dbType)); - } - case "EB": - // Input Byte - objValue = Convert.ChangeType(value, typeof(byte)); - return Write(DataType.Input, 0, int.Parse(txt.Substring(2)), (byte)objValue); - case "EW": - // Input Word - objValue = Convert.ChangeType(value, typeof(UInt16)); - return Write(DataType.Input, 0, int.Parse(txt.Substring(2)), (UInt16)objValue); - case "ED": - // Input Double-Word - objValue = Convert.ChangeType(value, typeof(UInt32)); - return Write(DataType.Input, 0, int.Parse(txt.Substring(2)), (UInt32)objValue); - case "AB": - // Output Byte - objValue = Convert.ChangeType(value, typeof(byte)); - return Write(DataType.Output, 0, int.Parse(txt.Substring(2)), (byte)objValue); - case "AW": - // Output Word - objValue = Convert.ChangeType(value, typeof(UInt16)); - return Write(DataType.Output, 0, int.Parse(txt.Substring(2)), (UInt16)objValue); - case "AD": - // Output Double-Word - objValue = Convert.ChangeType(value, typeof(UInt32)); - return Write(DataType.Output, 0, int.Parse(txt.Substring(2)), (UInt32)objValue); - case "MB": - // Memory Byte - objValue = Convert.ChangeType(value, typeof(byte)); - return Write(DataType.Memory, 0, int.Parse(txt.Substring(2)), (byte)objValue); - case "MW": - // Memory Word - objValue = Convert.ChangeType(value, typeof(UInt16)); - return Write(DataType.Memory, 0, int.Parse(txt.Substring(2)), (UInt16)objValue); - case "MD": - // Memory Double-Word - return Write(DataType.Memory, 0, int.Parse(txt.Substring(2)), value); - default: - switch (txt.Substring(0, 1)) - { - case "E": - case "I": - // Input - mDataType = DataType.Input; - break; - case "A": - case "O": - // Output - mDataType = DataType.Output; - break; - case "M": - // Memory - mDataType = DataType.Memory; - break; - case "T": - // Timer - return Write(DataType.Timer, 0, int.Parse(txt.Substring(1)), (double)value); - case "Z": - case "C": - // Counter - return Write(DataType.Counter, 0, int.Parse(txt.Substring(1)), (short)value); - default: - throw new Exception(string.Format("Unknown variable type {0}.", txt.Substring(0, 1))); - } - - addressLocation = txt.Substring(1); - int decimalPointIndex = addressLocation.IndexOf("."); - if (decimalPointIndex == -1) - { - throw new Exception(string.Format("Cannot parse variable {0}. Input, Output, Memory Address, Timer, and Counter types require bit-level addressing (e.g. I0.1).", addressLocation)); - } - - mByte = int.Parse(addressLocation.Substring(0, decimalPointIndex)); - mBit = int.Parse(addressLocation.Substring(decimalPointIndex + 1)); - if (mBit > 7) - { - throw new Exception(string.Format("Addressing Error: You can only reference bitwise locations 0-7. Address {0} is invalid", mBit)); - } - - _byte = (byte)Read(mDataType, 0, mByte, VarType.Byte, 1); - if ((int)value == 1) - _byte = (byte)(_byte | (byte)Math.Pow(2, mBit)); // Set bit - else - _byte = (byte)(_byte & (_byte ^ (byte)Math.Pow(2, mBit))); // Reset bit - - return Write(mDataType, 0, mByte, (byte)_byte); - } - } - catch - { - LastErrorCode = ErrorCode.WrongVarFormat; - LastErrorString = "The variable'" + variable + "' could not be parsed. Please check the syntax and try again."; - return LastErrorCode; - } - } - - /// - /// Writes a C# struct to a DB in the plc - /// - /// The struct to be written - /// Db address - /// Start bytes on the plc - /// NoError if it was successful, or the error is specified - public ErrorCode WriteStruct(object structValue, int db, int startByteAdr = 0) - { - var bytes = Types.Struct.ToBytes(structValue).ToList(); - var errCode = WriteMultipleBytes(bytes, db, startByteAdr); - return errCode; - } - - /// - /// Sets the LastErrorCode to NoError and LastErrorString to String.Empty - /// - public void ClearLastError() - { - LastErrorCode = ErrorCode.NoError; - LastErrorString = string.Empty; - } - - /// - /// Writes a C# class to a DB in the plc - /// - /// The class to be written - /// Db address - /// Start bytes on the plc - /// NoError if it was successful, or the error is specified - public ErrorCode WriteClass(object classValue, int db, int startByteAdr = 0) - { - var bytes = Types.Class.ToBytes(classValue).ToList(); - var errCode = WriteMultipleBytes(bytes, db, startByteAdr); - return errCode; - } - - /// - /// Writes multiple bytes to the plc. This uses recursion and it's not limited to 200 bytes. - /// - /// The bytes values to be written - /// Db address - /// Start bytes on the plc - /// NoError if it was successful, or the error is specified - private ErrorCode WriteMultipleBytes(List bytes, int db, int startByteAdr = 0) - { - ErrorCode errCode = ErrorCode.NoError; - int index = startByteAdr; - try - { - while (bytes.Count > 0) - { - var maxToWrite = Math.Min(bytes.Count, 200); - var part = bytes.ToList().GetRange(0, maxToWrite); - errCode = WriteBytes(DataType.DataBlock, db, index, part.ToArray()); - bytes.RemoveRange(0, maxToWrite); - index += maxToWrite; - if (errCode != ErrorCode.NoError) - { - break; - } - } - } - catch - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = "An error occurred while writing data."; - } - return errCode; - } - - /// - /// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests. - /// - /// Address of the memory area (if you want to read DB1, this is set to 1). This must be set also for other memory area types: counters, timers,etc. - /// Start byte address. If you want to read DB1.DBW200, this is 200. - /// Byte count, if you want to read 120 bytes, set this to 120. This parameter can't be higher than 200. If you need more, use recursion. - /// Returns the bytes in a list - private List ReadMultipleBytes(int numBytes, int db, int startByteAdr = 0) - { - List resultBytes = new List(); - int index = startByteAdr; - while (numBytes > 0) - { - var maxToRead = (int)Math.Min(numBytes, 200); - byte[] bytes = ReadBytes(DataType.DataBlock, db, index, maxToRead); - if (bytes == null) - return new List(); - resultBytes.AddRange(bytes); - numBytes -= maxToRead; - index += maxToRead; - } - return resultBytes; - } - - /// - /// Creates the header to read bytes from the plc - /// - /// - /// - private Types.ByteArray ReadHeaderPackage(int amount = 1) - { - //header size = 19 bytes - var package = new Types.ByteArray(19); - package.Add(new byte[] { 0x03, 0x00, 0x00 }); - //complete package size - package.Add((byte)(19 + (12 * amount))); - package.Add(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 }); - //data part size - package.Add(Types.Word.ToByteArray((ushort)(2 + (amount * 12)))); - package.Add(new byte[] { 0x00, 0x00, 0x04 }); - //amount of requests - package.Add((byte)amount); - - return package; - } - - /// - /// Create the bytes-package to request data from the plc. You have to specify the memory type (dataType), - /// the address of the memory, the address of the byte and the bytes count. - /// - /// MemoryType (DB, Timer, Counter, etc.) - /// Address of the memory to be read - /// Start address of the byte - /// Number of bytes to be read - /// - private Types.ByteArray CreateReadDataRequestPackage(DataType dataType, int db, int startByteAdr, int count = 1) - { - //single data req = 12 - var package = new Types.ByteArray(12); - package.Add(new byte[] { 0x12, 0x0a, 0x10 }); - switch (dataType) - { - case DataType.Timer: - case DataType.Counter: - package.Add((byte)dataType); - break; - default: - package.Add(0x02); - break; - } - - package.Add(Types.Word.ToByteArray((ushort)(count))); - package.Add(Types.Word.ToByteArray((ushort)(db))); - package.Add((byte)dataType); - var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191 - package.Add((byte)overflow); - switch (dataType) - { - case DataType.Timer: - case DataType.Counter: - package.Add(Types.Word.ToByteArray((ushort)(startByteAdr))); - break; - default: - package.Add(Types.Word.ToByteArray((ushort)((startByteAdr) * 8))); - break; - } - - return package; - } - - - - #region IDisposable members - - public void Dispose() - { - if (_mSocket != null) - { - if (_mSocket.Connected) - { - //Close() performs a Dispose on the socket. - _mSocket.Close(); - } - //((IDisposable)_mSocket).Dispose(); - } - } - - #endregion - } -} diff --git a/S7.Net.Core/S7.Net.Core.csproj b/S7.Net.Core/S7.Net.Core.csproj index 1f87265..2d16f96 100644 --- a/S7.Net.Core/S7.Net.Core.csproj +++ b/S7.Net.Core/S7.Net.Core.csproj @@ -107,16 +107,61 @@ - + + Conversion.cs + + + Enums.cs + + + PLC.cs + + + Types\Boolean.cs + + + Types\Byte.cs + + + Types\ByteArray.cs + + + Types\Class.cs + + + Types\Counter.cs + + + Types\DataItem.cs + + + Types\DInt.cs + + + Types\Double.cs + + + Types\DWord.cs + + + Types\Int.cs + + + Types\String.cs + + + Types\Struct.cs + + + Types\Timer.cs + + + Types\Word.cs + - - - %(RecursiveDir)%(FileName) - - 14.0 diff --git a/S7.Net.Core/SocketClient.cs b/S7.Net.Core/SocketClient.cs index 1902fd8..d78e8bf 100644 --- a/S7.Net.Core/SocketClient.cs +++ b/S7.Net.Core/SocketClient.cs @@ -66,7 +66,7 @@ namespace S7.Net _sendTimeout = milis; } - public int Send(byte[] buffer, int size) + public int Send(byte[] buffer, int size, SocketFlags socketFlag) { var response = 0; @@ -109,7 +109,7 @@ namespace S7.Net return response; } - public int Receive(byte[] buffer, int size) + public int Receive(byte[] buffer, int size, SocketFlags socketFlag) { var response = 0; @@ -170,4 +170,54 @@ namespace S7.Net private const int TIMEOUT_MILLISECONDS = 1000; } + + // + // Summary: + // Specifies socket send and receive behaviors. + [Flags] + public enum SocketFlags + { + // + // Summary: + // Use no flags for this call. + None = 0, + // + // Summary: + // Process out-of-band data. + OutOfBand = 1, + // + // Summary: + // Peek at the incoming message. + Peek = 2, + // + // Summary: + // Send without using routing tables. + DontRoute = 4, + // + // Summary: + // Provides a standard value for the number of WSABUF structures that are used to + // send and receive data. + MaxIOVectorLength = 16, + // + // Summary: + // The message was too large to fit into the specified buffer and was truncated. + Truncated = 256, + // + // Summary: + // Indicates that the control data did not fit into an internal 64-KB buffer and + // was truncated. + ControlDataTruncated = 512, + // + // Summary: + // Indicates a broadcast packet. + Broadcast = 1024, + // + // Summary: + // Indicates a multicast packet. + Multicast = 2048, + // + // Summary: + // Partial send or receive for message. + Partial = 32768 + } } \ No newline at end of file diff --git a/S7.Net/Conversion.cs b/S7.Net/Conversion.cs new file mode 100644 index 0000000..360e282 --- /dev/null +++ b/S7.Net/Conversion.cs @@ -0,0 +1,235 @@ +using System; +using System.Globalization; + +namespace S7.Net +{ + public static class Conversion + { + /// + /// Converts a binary string to Int32 value + /// + /// + /// + public static int BinStringToInt32(this string txt) + { + int cnt = 0; + int ret = 0; + + for (cnt = txt.Length - 1; cnt >= 0; cnt += -1) + { + if (int.Parse(txt.Substring(cnt, 1)) == 1) + { + ret += (int)(Math.Pow(2, (txt.Length - 1 - cnt))); + } + } + return ret; + } + + public static byte? BinStringToByte(this string txt) + { + int cnt = 0; + int ret = 0; + + if (txt.Length == 8) + { + for (cnt = 7; cnt >= 0; cnt += -1) + { + if (int.Parse(txt.Substring(cnt, 1)) == 1) + { + ret += (int)(Math.Pow(2, (txt.Length - 1 - cnt))); + } + } + return (byte)ret; + } + return null; + } + + /// + /// Converts the value to a binary string + /// + /// + /// + public static string ValToBinString(this object value) + { + int cnt = 0; + int cnt2 = 0; + int x = 0; + string txt = ""; + long longValue = 0; + + try + { + if (value.GetType().Name.IndexOf("[]") < 0) + { + // ist nur ein Wert + switch (value.GetType().Name) + { + case "Byte": + x = 7; + longValue = (long)((byte)value); + break; + case "Int16": + x = 15; + longValue = (long)((Int16)value); + break; + case "Int32": + x = 31; + longValue = (long)((Int32)value); + break; + case "Int64": + x = 63; + longValue = (long)((Int64)value); + break; + default: + throw new Exception(); + } + + for (cnt = x; cnt >= 0; cnt += -1) + { + if (((Int64)longValue & (Int64)Math.Pow(2, cnt)) > 0) + txt += "1"; + else + txt += "0"; + } + } + else + { + // ist ein Array + switch (value.GetType().Name) + { + case "Byte[]": + x = 7; + byte[] ByteArr = (byte[])value; + for (cnt2 = 0; cnt2 <= ByteArr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((ByteArr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int16[]": + x = 15; + Int16[] Int16Arr = (Int16[])value; + for (cnt2 = 0; cnt2 <= Int16Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int16Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int32[]": + x = 31; + Int32[] Int32Arr = (Int32[])value; + for (cnt2 = 0; cnt2 <= Int32Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int32Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + case "Int64[]": + x = 63; + byte[] Int64Arr = (byte[])value; + for (cnt2 = 0; cnt2 <= Int64Arr.Length - 1; cnt2++) + { + for (cnt = x; cnt >= 0; cnt += -1) + if ((Int64Arr[cnt2] & (byte)Math.Pow(2, cnt)) > 0) txt += "1"; else txt += "0"; + } + break; + default: + throw new Exception(); + } + } + return txt; + } + catch + { + return ""; + } + } + + /// + /// Helper to get a bit value given a byte and the bit index. + /// Example: DB1.DBX0.5 -> var bytes = ReadBytes(DB1.DBW0); bool bit = bytes[0].SelectBit(5); + /// + /// + /// + /// + public static bool SelectBit(this byte data, int bitPosition) + { + int mask = 1 << bitPosition; + int result = data & mask; + + return (result != 0); + } + + /// + /// Converts from ushort value to short value; it's used to retrieve negative values from words + /// + /// + /// + public static short ConvertToShort(this ushort input) + { + short output; + output = short.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from short value to ushort value; it's used to pass negative values to DWs + /// + /// + /// + public static ushort ConvertToUshort(this short input) + { + ushort output; + output = ushort.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from UInt32 value to Int32 value; it's used to retrieve negative values from DBDs + /// + /// + /// + public static Int32 ConvertToInt(this uint input) + { + int output; + output = int.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from Int32 value to UInt32 value; it's used to pass negative values to DBDs + /// + /// + /// + public static UInt32 ConvertToUInt(this int input) + { + uint output; + output = uint.Parse(input.ToString("X"), NumberStyles.HexNumber); + return output; + } + + /// + /// Converts from double to DWord (DBD) + /// + /// + /// + public static UInt32 ConvertToUInt(this double input) + { + uint output; + output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Double.ToByteArray(input)); + return output; + } + + /// + /// Converts from DWord (DBD) to double + /// + /// + /// + public static double ConvertToDouble(this uint input) + { + double output; + output = S7.Net.Types.Double.FromByteArray(S7.Net.Types.DWord.ToByteArray(input)); + return output; + } + } +} diff --git a/S7.Net/Enums.cs b/S7.Net/Enums.cs new file mode 100644 index 0000000..56aaa87 --- /dev/null +++ b/S7.Net/Enums.cs @@ -0,0 +1,51 @@ +namespace S7.Net +{ + public enum CpuType + { + S7200 = 0, + S7300 = 10, + S7400 = 20, + S71200 = 30, + S71500 = 40, + } + + public enum ErrorCode + { + NoError = 0, + WrongCPU_Type = 1, + ConnectionError = 2, + IPAddressNotAvailable, + + WrongVarFormat = 10, + WrongNumberReceivedBytes = 11, + + SendData = 20, + ReadData = 30, + + WriteData = 50 + } + + public enum DataType + { + Input = 129, + Output = 130, + Memory = 131, + DataBlock = 132, + Timer = 29, + Counter = 28 + } + + public enum VarType + { + Bit, + Byte, + Word, + DWord, + Int, + DInt, + Real, + String, + Timer, + Counter + } +} diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs index 2520485..a1d5751 100644 --- a/S7.Net/PLC.cs +++ b/S7.Net/PLC.cs @@ -12,7 +12,11 @@ namespace S7.Net { public class Plc : IDisposable { +#if NETFX_CORE + private SocketClient _mSocket; //TCP connection to device +#else private Socket _mSocket; //TCP connection to device +#endif /// /// Ip address of the plc @@ -33,7 +37,7 @@ namespace S7.Net /// Slot of the CPU of the plc /// public Int16 Slot { get; private set; } - + /// /// Pings the IP address and returns true if the result of the ping is Success. /// @@ -41,6 +45,9 @@ namespace S7.Net { get { +#if NETFX_CORE + return (!string.IsNullOrWhiteSpace(IP)); +#else using (Ping ping = new Ping()) { PingReply result; @@ -54,9 +61,11 @@ namespace S7.Net } return result != null && result.Status == IPStatus.Success; } +#endif } } + /// /// Checks if the socket is connected and polls the other peer (the plc) to see if it's connected. /// This is the variable that you should continously check to see if the communication is working @@ -70,8 +79,13 @@ namespace S7.Net { if (_mSocket == null) return false; + +#if NETFX_CORE + return _mSocket.Connected; +#else return !((_mSocket.Poll(1000, SelectMode.SelectRead) && (_mSocket.Available == 0)) || !_mSocket.Connected); - } +#endif + } catch { return false; } } } @@ -128,14 +142,10 @@ namespace S7.Net return LastErrorCode; } - try { - // open the channel - _mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - - _mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000); - _mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000); - - IPEndPoint server = new IPEndPoint(IPAddress.Parse(IP), 102); + try + { + CreateSocket(); + IPEndPoint server = new IPEndPoint(IPAddress.Parse(IP), 102); _mSocket.Connect(server); } catch (Exception ex) { @@ -324,7 +334,8 @@ namespace S7.Net byte[] bReceive = new byte[512]; int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None); - if (bReceive[21] != 0xff) throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); + if (bReceive[21] != 0xff) + throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString()); for (int cnt = 0; cnt < count; cnt++) bytes[cnt] = bReceive[cnt + 25]; @@ -1084,9 +1095,20 @@ namespace S7.Net return package; } + private void CreateSocket() + { +#if NETFX_CORE + _mSocket = new SocketClient(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _mSocket.SetReceiveTimeout(1000); + _mSocket.SetSendTimeout(1000); +#else + _mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000); + _mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000); +#endif + } - - #region IDisposable members +#region IDisposable members public void Dispose() { @@ -1099,8 +1121,7 @@ namespace S7.Net } //((IDisposable)_mSocket).Dispose(); } - } - - #endregion + } +#endregion } } diff --git a/S7.Net/S7.Net.csproj b/S7.Net/S7.Net.csproj index b496e12..ec08448 100644 --- a/S7.Net/S7.Net.csproj +++ b/S7.Net/S7.Net.csproj @@ -74,58 +74,24 @@ + + - - - - Conversion - - - Enums - - - Types\Boolean - - - Types\Byte - - - Types\ByteArray - - - Types\Class - - - Types\Counter - - - Types\DataItem - - - Types\DInt - - - Types\Double - - - Types\DWord - - - Types\Int - - - Types\String - - - Types\Struct - - - Types\Timer - - - Types\Word - + + + + + + + + + + + + + + @@ -142,6 +108,7 @@ +