diff --git a/S7.Net.UnitTest/Helpers/TestLongClass.cs b/S7.Net.UnitTest/Helpers/TestLongClass.cs new file mode 100644 index 0000000..5ce76c8 --- /dev/null +++ b/S7.Net.UnitTest/Helpers/TestLongClass.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace S7.UnitTest.Helpers +{ + /// + /// This is a class that contains more than 200 bytes and that needs 2 plc requests to complete a read/write cycle + /// + class TestLongClass + { + public short IntVariable0 { get; set; } + public short IntVariable1 { get; set; } + public short IntVariable2 { get; set; } + public short IntVariable3 { get; set; } + public short IntVariable4 { get; set; } + public short IntVariable5 { get; set; } + public short IntVariable6 { get; set; } + public short IntVariable7 { get; set; } + public short IntVariable8 { get; set; } + public short IntVariable9 { get; set; } + + public short IntVariable10 { get; set; } + public short IntVariable11 { get; set; } + public short IntVariable12 { get; set; } + public short IntVariable13 { get; set; } + public short IntVariable14 { get; set; } + public short IntVariable15 { get; set; } + public short IntVariable16 { get; set; } + public short IntVariable17 { get; set; } + public short IntVariable18 { get; set; } + public short IntVariable19 { get; set; } + + public short IntVariable20 { get; set; } + public short IntVariable21 { get; set; } + public short IntVariable22 { get; set; } + public short IntVariable23 { get; set; } + public short IntVariable24 { get; set; } + public short IntVariable25 { get; set; } + public short IntVariable26 { get; set; } + public short IntVariable27 { get; set; } + public short IntVariable28 { get; set; } + public short IntVariable29 { get; set; } + + public short IntVariable30 { get; set; } + public short IntVariable31 { get; set; } + public short IntVariable32 { get; set; } + public short IntVariable33 { get; set; } + public short IntVariable34 { get; set; } + public short IntVariable35 { get; set; } + public short IntVariable36 { get; set; } + public short IntVariable37 { get; set; } + public short IntVariable38 { get; set; } + public short IntVariable39 { get; set; } + + public short IntVariable40 { get; set; } + public short IntVariable41 { get; set; } + public short IntVariable42 { get; set; } + public short IntVariable43 { get; set; } + public short IntVariable44 { get; set; } + public short IntVariable45 { get; set; } + public short IntVariable46 { get; set; } + public short IntVariable47 { get; set; } + public short IntVariable48 { get; set; } + public short IntVariable49 { get; set; } + + public short IntVariable50 { get; set; } + public short IntVariable51 { get; set; } + public short IntVariable52 { get; set; } + public short IntVariable53 { get; set; } + public short IntVariable54 { get; set; } + public short IntVariable55 { get; set; } + public short IntVariable56 { get; set; } + public short IntVariable57 { get; set; } + public short IntVariable58 { get; set; } + public short IntVariable59 { get; set; } + + public short IntVariable60 { get; set; } + public short IntVariable61 { get; set; } + public short IntVariable62 { get; set; } + public short IntVariable63 { get; set; } + public short IntVariable64 { get; set; } + public short IntVariable65 { get; set; } + public short IntVariable66 { get; set; } + public short IntVariable67 { get; set; } + public short IntVariable68 { get; set; } + public short IntVariable69 { get; set; } + + public short IntVariable70 { get; set; } + public short IntVariable71 { get; set; } + public short IntVariable72 { get; set; } + public short IntVariable73 { get; set; } + public short IntVariable74 { get; set; } + public short IntVariable75 { get; set; } + public short IntVariable76 { get; set; } + public short IntVariable77 { get; set; } + public short IntVariable78 { get; set; } + public short IntVariable79 { get; set; } + + public short IntVariable80 { get; set; } + public short IntVariable81 { get; set; } + public short IntVariable82 { get; set; } + public short IntVariable83 { get; set; } + public short IntVariable84 { get; set; } + public short IntVariable85 { get; set; } + public short IntVariable86 { get; set; } + public short IntVariable87 { get; set; } + public short IntVariable88 { get; set; } + public short IntVariable89 { get; set; } + + public short IntVariable90 { get; set; } + public short IntVariable91 { get; set; } + public short IntVariable92 { get; set; } + public short IntVariable93 { get; set; } + public short IntVariable94 { get; set; } + public short IntVariable95 { get; set; } + public short IntVariable96 { get; set; } + public short IntVariable97 { get; set; } + public short IntVariable98 { get; set; } + public short IntVariable99 { get; set; } + + public short IntVariable100 { get; set; } + public short IntVariable101 { get; set; } + public short IntVariable102 { get; set; } + public short IntVariable103 { get; set; } + public short IntVariable104 { get; set; } + public short IntVariable105 { get; set; } + public short IntVariable106 { get; set; } + public short IntVariable107 { get; set; } + public short IntVariable108 { get; set; } + public short IntVariable109 { get; set; } + + public short IntVariable110 { get; set; } + public short IntVariable111 { get; set; } + public short IntVariable112 { get; set; } + public short IntVariable113 { get; set; } + public short IntVariable114 { get; set; } + public short IntVariable115 { get; set; } + public short IntVariable116 { get; set; } + public short IntVariable117 { get; set; } + public short IntVariable118 { get; set; } + public short IntVariable119 { get; set; } + } +} diff --git a/S7.Net.UnitTest/Helpers/TestLongStruct.cs b/S7.Net.UnitTest/Helpers/TestLongStruct.cs new file mode 100644 index 0000000..7c68356 --- /dev/null +++ b/S7.Net.UnitTest/Helpers/TestLongStruct.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace S7.UnitTest.Helpers +{ + /// + /// This is a struct that contains more than 200 bytes and that needs 2 plc requests to complete a read/write cycle + /// + struct TestLongStruct + { + // these variables are not used, but are needed to match the size of the DB +#pragma warning disable 0649 + + + public short IntVariable0; + public short IntVariable1; + public short IntVariable2; + public short IntVariable3; + public short IntVariable4; + public short IntVariable5; + public short IntVariable6; + public short IntVariable7; + public short IntVariable8; + public short IntVariable9; + + public short IntVariable10; + public short IntVariable11; + public short IntVariable12; + public short IntVariable13; + public short IntVariable14; + public short IntVariable15; + public short IntVariable16; + public short IntVariable17; + public short IntVariable18; + public short IntVariable19; + + public short IntVariable20; + public short IntVariable21; + public short IntVariable22; + public short IntVariable23; + public short IntVariable24; + public short IntVariable25; + public short IntVariable26; + public short IntVariable27; + public short IntVariable28; + public short IntVariable29; + + public short IntVariable30; + public short IntVariable31; + public short IntVariable32; + public short IntVariable33; + public short IntVariable34; + public short IntVariable35; + public short IntVariable36; + public short IntVariable37; + public short IntVariable38; + public short IntVariable39; + + public short IntVariable40; + public short IntVariable41; + public short IntVariable42; + public short IntVariable43; + public short IntVariable44; + public short IntVariable45; + public short IntVariable46; + public short IntVariable47; + public short IntVariable48; + public short IntVariable49; + + public short IntVariable50; + public short IntVariable51; + public short IntVariable52; + public short IntVariable53; + public short IntVariable54; + public short IntVariable55; + public short IntVariable56; + public short IntVariable57; + public short IntVariable58; + public short IntVariable59; + + public short IntVariable60; + public short IntVariable61; + public short IntVariable62; + public short IntVariable63; + public short IntVariable64; + public short IntVariable65; + public short IntVariable66; + public short IntVariable67; + public short IntVariable68; + public short IntVariable69; + + public short IntVariable70; + public short IntVariable71; + public short IntVariable72; + public short IntVariable73; + public short IntVariable74; + public short IntVariable75; + public short IntVariable76; + public short IntVariable77; + public short IntVariable78; + public short IntVariable79; + + public short IntVariable80; + public short IntVariable81; + public short IntVariable82; + public short IntVariable83; + public short IntVariable84; + public short IntVariable85; + public short IntVariable86; + public short IntVariable87; + public short IntVariable88; + public short IntVariable89; + + public short IntVariable90; + public short IntVariable91; + public short IntVariable92; + public short IntVariable93; + public short IntVariable94; + public short IntVariable95; + public short IntVariable96; + public short IntVariable97; + public short IntVariable98; + public short IntVariable99; + + public short IntVariable100; + public short IntVariable101; + public short IntVariable102; + public short IntVariable103; + public short IntVariable104; + public short IntVariable105; + public short IntVariable106; + public short IntVariable107; + public short IntVariable108; + public short IntVariable109; + + public short IntVariable110; + public short IntVariable111; + public short IntVariable112; + public short IntVariable113; + public short IntVariable114; + public short IntVariable115; + public short IntVariable116; + public short IntVariable117; + public short IntVariable118; + public short IntVariable119; + +#pragma warning restore 0649 + + } +} diff --git a/S7.Net.UnitTest/S7.Net.UnitTest.csproj b/S7.Net.UnitTest/S7.Net.UnitTest.csproj index 202e509..e148f86 100644 --- a/S7.Net.UnitTest/S7.Net.UnitTest.csproj +++ b/S7.Net.UnitTest/S7.Net.UnitTest.csproj @@ -55,11 +55,13 @@ + + diff --git a/S7.Net.UnitTest/S7NetTests.cs b/S7.Net.UnitTest/S7NetTests.cs index 51ca5b7..652ef7d 100644 --- a/S7.Net.UnitTest/S7NetTests.cs +++ b/S7.Net.UnitTest/S7NetTests.cs @@ -4,7 +4,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using S7.Net; using S7.Net.UnitTest.Helpers; using S7.Net.UnitTest; -using System.ServiceProcess; +using System.ServiceProcess; +using S7.UnitTest.Helpers; #endregion @@ -185,7 +186,136 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.IntVariable, tc2.IntVariable); Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3)); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); - } + } + + /// + /// Read/Write a struct that has the same properties of a DB with the same field in the same order + /// + [TestMethod] + public void T06_ReadAndWriteLongStruct() + { + Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor."); + + TestLongStruct tc = new TestLongStruct(); + tc.IntVariable0 = 0; + tc.IntVariable1 = 1; + tc.IntVariable10 = 10; + tc.IntVariable11 = 11; + tc.IntVariable20 = 20; + tc.IntVariable21 = 21; + tc.IntVariable30 = 30; + tc.IntVariable31 = 31; + tc.IntVariable40 = 40; + tc.IntVariable41 = 41; + tc.IntVariable50 = 50; + tc.IntVariable51 = 51; + tc.IntVariable60 = 60; + tc.IntVariable61 = 61; + tc.IntVariable70 = 70; + tc.IntVariable71 = 71; + tc.IntVariable80 = 80; + tc.IntVariable81 = 81; + tc.IntVariable90 = 90; + tc.IntVariable91 = 91; + tc.IntVariable100 = 100; + tc.IntVariable101 = 101; + tc.IntVariable110 = 200; + tc.IntVariable111 = 201; + plc.WriteStruct(tc, DB2); + Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); + // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct + TestLongStruct tc2 = (TestLongStruct)plc.ReadStruct(typeof(TestLongStruct), DB2); + Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); + Assert.AreEqual( tc.IntVariable0, tc2.IntVariable0 ); + Assert.AreEqual( tc.IntVariable1, tc2.IntVariable1 ); + Assert.AreEqual( tc.IntVariable10, tc2.IntVariable10); + Assert.AreEqual( tc.IntVariable11, tc2.IntVariable11); + Assert.AreEqual( tc.IntVariable20, tc2.IntVariable20); + Assert.AreEqual( tc.IntVariable21, tc2.IntVariable21); + Assert.AreEqual( tc.IntVariable30, tc2.IntVariable30); + Assert.AreEqual( tc.IntVariable31, tc2.IntVariable31); + Assert.AreEqual( tc.IntVariable40, tc2.IntVariable40); + Assert.AreEqual( tc.IntVariable41, tc2.IntVariable41); + Assert.AreEqual( tc.IntVariable50, tc2.IntVariable50); + Assert.AreEqual( tc.IntVariable51, tc2.IntVariable51); + Assert.AreEqual( tc.IntVariable60, tc2.IntVariable60); + Assert.AreEqual( tc.IntVariable61, tc2.IntVariable61); + Assert.AreEqual( tc.IntVariable70, tc2.IntVariable70); + Assert.AreEqual( tc.IntVariable71, tc2.IntVariable71); + Assert.AreEqual( tc.IntVariable80, tc2.IntVariable80); + Assert.AreEqual( tc.IntVariable81, tc2.IntVariable81); + Assert.AreEqual( tc.IntVariable90, tc2.IntVariable90); + Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91); + Assert.AreEqual(tc.IntVariable100, tc2.IntVariable100); + Assert.AreEqual(tc.IntVariable101, tc2.IntVariable101); + Assert.AreEqual(tc.IntVariable110, tc2.IntVariable110); + Assert.AreEqual(tc.IntVariable111, tc2.IntVariable111); + } + + /// + /// Read/Write a class that has the same properties of a DB with the same field in the same order + /// + [TestMethod] + public void T07_ReadAndWriteLongClass() + { + Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor."); + + TestLongClass tc = new TestLongClass(); + tc.IntVariable0 = 0; + tc.IntVariable1 = 1; + tc.IntVariable10 = 10; + tc.IntVariable11 = 11; + tc.IntVariable20 = 20; + tc.IntVariable21 = 21; + tc.IntVariable30 = 30; + tc.IntVariable31 = 31; + tc.IntVariable40 = 40; + tc.IntVariable41 = 41; + tc.IntVariable50 = 50; + tc.IntVariable51 = 51; + tc.IntVariable60 = 60; + tc.IntVariable61 = 61; + tc.IntVariable70 = 70; + tc.IntVariable71 = 71; + tc.IntVariable80 = 80; + tc.IntVariable81 = 81; + tc.IntVariable90 = 90; + tc.IntVariable91 = 91; + tc.IntVariable100 = 100; + tc.IntVariable101 = 101; + tc.IntVariable110 = 200; + tc.IntVariable111 = 201; + plc.WriteClass(tc, DB2); + Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); + // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct + TestLongClass tc2 = new TestLongClass(); + plc.ReadClass(tc2, DB2); + Assert.AreEqual(ErrorCode.NoError, plc.LastErrorCode); + Assert.AreEqual(tc.IntVariable0, tc2.IntVariable0); + Assert.AreEqual(tc.IntVariable1, tc2.IntVariable1); + Assert.AreEqual(tc.IntVariable10, tc2.IntVariable10); + Assert.AreEqual(tc.IntVariable11, tc2.IntVariable11); + Assert.AreEqual(tc.IntVariable20, tc2.IntVariable20); + Assert.AreEqual(tc.IntVariable21, tc2.IntVariable21); + Assert.AreEqual(tc.IntVariable30, tc2.IntVariable30); + Assert.AreEqual(tc.IntVariable31, tc2.IntVariable31); + Assert.AreEqual(tc.IntVariable40, tc2.IntVariable40); + Assert.AreEqual(tc.IntVariable41, tc2.IntVariable41); + Assert.AreEqual(tc.IntVariable50, tc2.IntVariable50); + Assert.AreEqual(tc.IntVariable51, tc2.IntVariable51); + Assert.AreEqual(tc.IntVariable60, tc2.IntVariable60); + Assert.AreEqual(tc.IntVariable61, tc2.IntVariable61); + Assert.AreEqual(tc.IntVariable70, tc2.IntVariable70); + Assert.AreEqual(tc.IntVariable71, tc2.IntVariable71); + Assert.AreEqual(tc.IntVariable80, tc2.IntVariable80); + Assert.AreEqual(tc.IntVariable81, tc2.IntVariable81); + Assert.AreEqual(tc.IntVariable90, tc2.IntVariable90); + Assert.AreEqual(tc.IntVariable91, tc2.IntVariable91); + Assert.AreEqual(tc.IntVariable100, tc2.IntVariable100); + Assert.AreEqual(tc.IntVariable101, tc2.IntVariable101); + Assert.AreEqual(tc.IntVariable110, tc2.IntVariable110); + Assert.AreEqual(tc.IntVariable111, tc2.IntVariable111); + } #endregion diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs index dfbbb5f..bf63dda 100644 --- a/S7.Net/PLC.cs +++ b/S7.Net/PLC.cs @@ -1,5 +1,7 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -505,11 +507,12 @@ namespace S7.Net public object ReadStruct(Type structType, int db) { - double numBytes = Types.Struct.GetStructSize(structType); + int numBytes = Types.Struct.GetStructSize(structType); // now read the package - byte[] bytes = (byte[])Read(DataType.DataBlock, db, 0, VarType.Byte, (int)numBytes); + List resultBytes = ReadMultipleBytes(numBytes, db); + // and decode it - return Types.Struct.FromBytes(structType, bytes); + return Types.Struct.FromBytes(structType, resultBytes.ToArray()); } /// @@ -520,11 +523,11 @@ namespace S7.Net public void ReadClass(object sourceClass, int db) { Type classType = sourceClass.GetType(); - double numBytes = Types.Class.GetClassSize(classType); + int numBytes = Types.Class.GetClassSize(classType); // now read the package - byte[] bytes = (byte[])Read(DataType.DataBlock, db, 0, VarType.Byte, (int)numBytes); + List resultBytes = ReadMultipleBytes(numBytes, db); // and decode it - Types.Class.FromBytes(sourceClass, classType, bytes); + Types.Class.FromBytes(sourceClass, classType, resultBytes.ToArray()); } public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value) @@ -794,36 +797,76 @@ namespace S7.Net public ErrorCode WriteStruct(object structValue, int db) { - try - { - byte[] bytes = Types.Struct.ToBytes(structValue); - ErrorCode errCode = WriteBytes(DataType.DataBlock, db, 0, bytes); - return errCode; - } - catch - { - LastErrorCode = ErrorCode.WriteData; - LastErrorString = "An error occurred while writing data."; - return LastErrorCode; - } + var bytes = Types.Struct.ToBytes(structValue).ToList(); + var errCode = WriteMultipleBytes(bytes, db); + return errCode; } public ErrorCode WriteClass(object classValue, int db) { + var bytes = Types.Class.ToBytes(classValue).ToList(); + var errCode = WriteMultipleBytes(bytes, db); + return errCode; + } + + /// + /// Writes multiple bytes in a DB starting from index 0. This handles more than 200 bytes with multiple requests. + /// + /// The bytes to be written + /// The DB number + /// ErrorCode when writing (NoError if everything was ok) + private ErrorCode WriteMultipleBytes(List bytes, int db) + { + ErrorCode errCode = ErrorCode.NoError; + int index = 0; try { - byte[] bytes = Types.Class.ToBytes(classValue); - ErrorCode errCode = WriteBytes(DataType.DataBlock, db, 0, bytes); - return errCode; + 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 LastErrorCode; } + return errCode; } + /// + /// Reads a number of bytes from a DB starting from index 0. This handles more than 200 bytes with multiple requests. + /// + /// + /// + /// + private List ReadMultipleBytes(int numBytes, int db) + { + List resultBytes = new List(); + int index = 0; + while (numBytes > 0) + { + var maxToRead = (int)Math.Min(numBytes, 200); + byte[] bytes = (byte[])Read(DataType.DataBlock, db, index, VarType.Byte, (int)maxToRead); + resultBytes.AddRange(bytes); + numBytes -= maxToRead; + index += maxToRead; + } + return resultBytes; + } + + + + #region IDisposable members + public void Dispose() { if (_mSocket != null) @@ -835,6 +878,8 @@ namespace S7.Net } //((IDisposable)_mSocket).Dispose(); } - } + } + + #endregion } }