Read/Write class and structs now handle more than 200 bytes with multiple requests (Issue #30 and Issue #27).

Signed-off-by: Michele Cattafesta <michele.cattafesta@mesta-automation.com>
This commit is contained in:
Michele Cattafesta
2015-10-05 23:44:49 +02:00
parent a6307baa8c
commit 9aa01a4aad
5 changed files with 499 additions and 25 deletions

View File

@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace S7.UnitTest.Helpers
{
/// <summary>
/// This is a class that contains more than 200 bytes and that needs 2 plc requests to complete a read/write cycle
/// </summary>
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; }
}
}

View File

@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace S7.UnitTest.Helpers
{
/// <summary>
/// This is a struct that contains more than 200 bytes and that needs 2 plc requests to complete a read/write cycle
/// </summary>
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
}
}

View File

@@ -55,11 +55,13 @@
<Compile Include="Helpers\ConsoleManager.cs" />
<Compile Include="Helpers\NativeMethods.cs" />
<Compile Include="Helpers\S7TestServer.cs" />
<Compile Include="Helpers\TestLongClass.cs" />
<Compile Include="Snap7\snap7.net.cs" />
<Compile Include="Helpers\TestClass.cs" />
<Compile Include="Helpers\TestStruct.cs" />
<Compile Include="S7NetTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helpers\TestLongStruct.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="snap7.dll">

View File

@@ -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);
}
}
/// <summary>
/// Read/Write a struct that has the same properties of a DB with the same field in the same order
/// </summary>
[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);
}
/// <summary>
/// Read/Write a class that has the same properties of a DB with the same field in the same order
/// </summary>
[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

View File

@@ -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<byte> resultBytes = ReadMultipleBytes(numBytes, db);
// and decode it
return Types.Struct.FromBytes(structType, bytes);
return Types.Struct.FromBytes(structType, resultBytes.ToArray());
}
/// <summary>
@@ -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<byte> 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;
}
/// <summary>
/// Writes multiple bytes in a DB starting from index 0. This handles more than 200 bytes with multiple requests.
/// </summary>
/// <param name="bytes">The bytes to be written</param>
/// <param name="db">The DB number</param>
/// <returns>ErrorCode when writing (NoError if everything was ok)</returns>
private ErrorCode WriteMultipleBytes(List<byte> 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;
}
/// <summary>
/// Reads a number of bytes from a DB starting from index 0. This handles more than 200 bytes with multiple requests.
/// </summary>
/// <param name="numBytes"></param>
/// <param name="db"></param>
/// <returns></returns>
private List<byte> ReadMultipleBytes(int numBytes, int db)
{
List<byte> resultBytes = new List<byte>();
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
}
}