diff --git a/S7.Net.UnitTest/S7NetTestsAsync.cs b/S7.Net.UnitTest/S7NetTestsAsync.cs
index 38f12af..e03a490 100644
--- a/S7.Net.UnitTest/S7NetTestsAsync.cs
+++ b/S7.Net.UnitTest/S7NetTestsAsync.cs
@@ -128,6 +128,26 @@ namespace S7.Net.UnitTest
Assert.AreEqual(val3, result3);
}
+ ///
+ /// Write/Read a large amount of data to test PDU max
+ ///
+ [TestMethod]
+ public async Task Test_Async_WriteLargeByteArray()
+ {
+ Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
+
+ var randomEngine = new Random();
+ var data = new byte[8192];
+ var db = 2;
+ randomEngine.NextBytes(data);
+
+ await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data);
+
+ var readData = await plc.ReadBytesAsync(DataType.DataBlock, db, 0, data.Length);
+
+ CollectionAssert.AreEqual(data, readData);
+ }
+
///
/// Read/Write a class that has the same properties of a DB with the same field in the same order
///
diff --git a/S7.Net.UnitTest/S7NetTestsSync.cs b/S7.Net.UnitTest/S7NetTestsSync.cs
index 3b7589b..e2e563e 100644
--- a/S7.Net.UnitTest/S7NetTestsSync.cs
+++ b/S7.Net.UnitTest/S7NetTestsSync.cs
@@ -743,6 +743,26 @@ namespace S7.Net.UnitTest
Assert.AreEqual(tc.ShortVariable04.ShortVarialbe00, tc2.ShortVariable04.ShortVarialbe00);
}
+ ///
+ /// Write/Read a large amount of data to test PDU max
+ ///
+ [TestMethod]
+ public void T33_WriteLargeByteArray()
+ {
+ Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
+
+ var randomEngine = new Random();
+ var data = new byte[8192];
+ var db = 2;
+ randomEngine.NextBytes(data);
+
+ plc.WriteBytes(DataType.DataBlock, db, 0, data);
+
+ var readData = plc.ReadBytes(DataType.DataBlock, db, 0, data.Length);
+
+ CollectionAssert.AreEqual(data, readData);
+ }
+
[TestMethod, ExpectedException(typeof(PlcException))]
public void T18_ReadStructThrowsIfPlcIsNotConnected()
{
diff --git a/S7.Net/COTP.cs b/S7.Net/COTP.cs
index 8f60423..c4af73a 100644
--- a/S7.Net/COTP.cs
+++ b/S7.Net/COTP.cs
@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
-using System.Linq;
namespace S7.Net
{
@@ -27,17 +26,17 @@ namespace S7.Net
{
TPkt = tPKT;
- var br = new BinaryReader(new MemoryStream(tPKT.Data));
- HeaderLength = br.ReadByte();
+ HeaderLength = tPKT.Data[0]; // Header length excluding this length byte
if (HeaderLength >= 2)
{
- PDUType = br.ReadByte();
+ PDUType = tPKT.Data[1];
if (PDUType == 0xf0) //DT Data
{
- var flags = br.ReadByte();
+ var flags = tPKT.Data[2];
TPDUNumber = flags & 0x7F;
LastDataUnit = (flags & 0x80) > 0;
- Data = br.ReadBytes(tPKT.Length - HeaderLength - 4); //4 = TPKT Size
+ Data = new byte[tPKT.Data.Length - HeaderLength - 1]; // substract header length byte + header length.
+ Array.Copy(tPKT.Data, HeaderLength + 1, Data, 0, Data.Length);
return;
}
//TODO: Handle other PDUTypes
@@ -105,20 +104,24 @@ namespace S7.Net
{
var segment = TPDU.Read(stream);
+ if (segment.LastDataUnit)
+ {
+ return segment.Data;
+ }
+
+ // More segments are expected, prepare a buffer to store all data
var buffer = new byte[segment.Data.Length];
- var output = new MemoryStream(buffer);
- output.Write(segment.Data, 0, segment.Data.Length);
+ Array.Copy(segment.Data, buffer, segment.Data.Length);
while (!segment.LastDataUnit)
{
segment = TPDU.Read(stream);
+ var previousLength = buffer.Length;
Array.Resize(ref buffer, buffer.Length + segment.Data.Length);
- var lastPosition = output.Position;
- output = new MemoryStream(buffer);
- output.Write(segment.Data, (int) lastPosition, segment.Data.Length);
+ Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length);
}
- return buffer.Take((int)output.Position).ToArray();
+ return buffer;
}
///
@@ -131,19 +134,24 @@ namespace S7.Net
{
var segment = await TPDU.ReadAsync(stream);
+ if (segment.LastDataUnit)
+ {
+ return segment.Data;
+ }
+
+ // More segments are expected, prepare a buffer to store all data
var buffer = new byte[segment.Data.Length];
- var output = new MemoryStream(buffer);
- output.Write(segment.Data, 0, segment.Data.Length);
+ Array.Copy(segment.Data, buffer, segment.Data.Length);
while (!segment.LastDataUnit)
{
segment = await TPDU.ReadAsync(stream);
+ var previousLength = buffer.Length;
Array.Resize(ref buffer, buffer.Length + segment.Data.Length);
- var lastPosition = output.Position;
- output = new MemoryStream(buffer);
- output.Write(segment.Data, (int) lastPosition, segment.Data.Length);
+ Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length);
}
- return buffer.Take((int)output.Position).ToArray();
+
+ return buffer;
}
}
}
diff --git a/S7.Net/Helper/MemoryStreamExtension.cs b/S7.Net/Helper/MemoryStreamExtension.cs
new file mode 100644
index 0000000..dd10fbc
--- /dev/null
+++ b/S7.Net/Helper/MemoryStreamExtension.cs
@@ -0,0 +1,18 @@
+
+namespace S7.Net.Helper
+{
+ internal static class MemoryStreamExtension
+ {
+ ///
+ /// Helper function to write to whole content of the given byte array to a memory stream.
+ ///
+ /// Writes all bytes in value from 0 to value.Length to the memory stream.
+ ///
+ ///
+ ///
+ public static void WriteByteArray(this System.IO.MemoryStream stream, byte[] value)
+ {
+ stream.Write(value, 0, value.Length);
+ }
+ }
+}
diff --git a/S7.Net/PLCHelpers.cs b/S7.Net/PLCHelpers.cs
index 2286264..9325f8a 100644
--- a/S7.Net/PLCHelpers.cs
+++ b/S7.Net/PLCHelpers.cs
@@ -1,4 +1,5 @@
-using S7.Net.Types;
+using S7.Net.Helper;
+using S7.Net.Types;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,21 +14,18 @@ namespace S7.Net
///
///
///
- private ByteArray ReadHeaderPackage(int amount = 1)
+ private void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
{
//header size = 19 bytes
- var package = new Types.ByteArray(19);
- package.Add(new byte[] { 0x03, 0x00 });
+ stream.WriteByteArray(new byte[] { 0x03, 0x00 });
//complete package size
- package.Add(Types.Int.ToByteArray((short)(19 + (12 * amount))));
- package.Add(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
+ stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
+ stream.WriteByteArray(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 });
+ stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12))));
+ stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 });
//amount of requests
- package.Add((byte)amount);
-
- return package;
+ stream.WriteByte((byte)amount);
}
///
@@ -39,39 +37,36 @@ namespace S7.Net
/// Start address of the byte
/// Number of bytes to be read
///
- private ByteArray CreateReadDataRequestPackage(DataType dataType, int db, int startByteAdr, int count = 1)
+ private void BuildReadDataRequestPackage(System.IO.MemoryStream stream, 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 });
+ stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 });
switch (dataType)
{
case DataType.Timer:
case DataType.Counter:
- package.Add((byte)dataType);
+ stream.WriteByte((byte)dataType);
break;
default:
- package.Add(0x02);
+ stream.WriteByte(0x02);
break;
}
- package.Add(Word.ToByteArray((ushort)(count)));
- package.Add(Word.ToByteArray((ushort)(db)));
- package.Add((byte)dataType);
+ stream.WriteByteArray(Word.ToByteArray((ushort)(count)));
+ stream.WriteByteArray(Word.ToByteArray((ushort)(db)));
+ stream.WriteByte((byte)dataType);
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
- package.Add((byte)overflow);
+ stream.WriteByte((byte)overflow);
switch (dataType)
{
case DataType.Timer:
case DataType.Counter:
- package.Add(Types.Word.ToByteArray((ushort)(startByteAdr)));
+ stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr)));
break;
default:
- package.Add(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
+ stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
break;
}
-
- return package;
}
///
diff --git a/S7.Net/PlcAsynchronous.cs b/S7.Net/PlcAsynchronous.cs
index 601a3a4..6a63ddd 100644
--- a/S7.Net/PlcAsynchronous.cs
+++ b/S7.Net/PlcAsynchronous.cs
@@ -39,11 +39,16 @@ namespace S7.Net
var s7data = await COTP.TSDU.ReadAsync(stream);
if (s7data == null)
throw new WrongNumberOfBytesException("No data received in response to Communication Setup");
+ if (s7data.Length < 2)
+ throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
//Check for S7 Ack Data
if (s7data[1] != 0x03)
throw new InvalidDataException("Error reading Communication Setup response", s7data, 1, 0x03);
+ if (s7data.Length < 20)
+ throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
+
MaxPDUSize = (short)(s7data[18] * 256 + s7data[19]);
}
@@ -67,20 +72,17 @@ namespace S7.Net
/// Returns the bytes in an array
public async Task ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count)
{
- List resultBytes = new List();
- int index = startByteAdr;
+ var resultBytes = new byte[count];
+ int index = 0;
while (count > 0)
{
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
- var maxToRead = (int)Math.Min(count, MaxPDUSize - 18);
- byte[] bytes = await ReadBytesWithSingleRequestAsync(dataType, db, index, maxToRead);
- if (bytes == null)
- return resultBytes.ToArray();
- resultBytes.AddRange(bytes);
+ var maxToRead = Math.Min(count, MaxPDUSize - 18);
+ await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead);
count -= maxToRead;
index += maxToRead;
}
- return resultBytes.ToArray();
+ return resultBytes;
}
///
@@ -222,15 +224,16 @@ namespace S7.Net
{
// first create the header
int packageSize = 19 + (dataItems.Count * 12);
- ByteArray package = new ByteArray(packageSize);
- package.Add(ReadHeaderPackage(dataItems.Count));
+ var package = new System.IO.MemoryStream(packageSize);
+ BuildHeaderPackage(package, 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)));
+ BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count));
}
- await stream.WriteAsync(package.Array, 0, package.Array.Length);
+ var dataToSend = package.ToArray();
+ await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
var s7data = await COTP.TSDU.ReadAsync(stream); //TODO use Async
if (s7data == null || s7data[14] != 0xff)
@@ -264,11 +267,8 @@ namespace S7.Net
int count = value.Length;
while (count > 0)
{
- //TODO: Figure out how to use MaxPDUSize here
- //Snap7 seems to choke on PDU sizes above 256 even if snap7
- //replies with bigger PDU size in connection setup.
- var maxToWrite = (int)Math.Min(count, 200);
- await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray());
+ var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35);
+ await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite);
count -= maxToWrite;
localIndex += maxToWrite;
}
@@ -383,28 +383,24 @@ namespace S7.Net
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes);
}
- private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, int count)
+ private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
{
var stream = GetStreamIfAvailable();
- byte[] bytes = new byte[count];
-
// first create the header
- int packageSize = 31;
- ByteArray package = new ByteArray(packageSize);
- package.Add(ReadHeaderPackage());
+ int packageSize = 31;
+ var package = new System.IO.MemoryStream(packageSize);
+ BuildHeaderPackage(package);
// package.Add(0x02); // datenart
- package.Add(CreateReadDataRequestPackage(dataType, db, startByteAdr, count));
+ BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
- await stream.WriteAsync(package.Array, 0, package.Array.Length);
+ var dataToSend = package.ToArray();
+ await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
var s7data = await COTP.TSDU.ReadAsync(stream);
AssertReadResponse(s7data, count);
- for (int cnt = 0; cnt < count; cnt++)
- bytes[cnt] = s7data[cnt + 18];
-
- return bytes;
+ Array.Copy(s7data, 18, buffer, offset, count);
}
///
@@ -435,40 +431,15 @@ namespace S7.Net
/// 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.
/// A task that represents the asynchronous write operation.
- private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value)
+ private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
{
- var stream = GetStreamIfAvailable();
-
- byte[] bReceive = new byte[513];
- int varCount = 0;
try
{
- varCount = value.Length;
- // first create the header
- int packageSize = 35 + value.Length;
- ByteArray package = new ByteArray(packageSize);
+ var stream = GetStreamIfAvailable();
+ var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
- package.Add(new byte[] { 3, 0, 0 });
- package.Add((byte)packageSize);
- package.Add(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
- package.Add(Word.ToByteArray((ushort)(varCount - 1)));
- package.Add(new byte[] { 0, 0x0e });
- package.Add(Word.ToByteArray((ushort)(varCount + 4)));
- package.Add(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
- package.Add(Word.ToByteArray((ushort)varCount));
- package.Add(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(Word.ToByteArray((ushort)(startByteAdr * 8)));
- package.Add(new byte[] { 0, 4 });
- package.Add(Word.ToByteArray((ushort)(varCount * 8)));
-
- // now join the header and the data
- package.Add(value);
-
- await stream.WriteAsync(package.Array, 0, package.Array.Length);
+ await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
var s7data = await COTP.TSDU.ReadAsync(stream);
if (s7data == null || s7data[14] != 0xff)
@@ -486,41 +457,17 @@ namespace S7.Net
{
var stream = GetStreamIfAvailable();
- byte[] bReceive = new byte[513];
- int varCount = 0;
-
try
{
- var value = new[] {bitValue ? (byte) 1 : (byte) 0};
- varCount = value.Length;
- // first create the header
- int packageSize = 35 + value.Length;
- ByteArray package = new Types.ByteArray(packageSize);
+ var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
- package.Add(new byte[] { 3, 0, 0 });
- package.Add((byte)packageSize);
- package.Add(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
- package.Add(Word.ToByteArray((ushort)(varCount - 1)));
- package.Add(new byte[] { 0, 0x0e });
- package.Add(Word.ToByteArray((ushort)(varCount + 4)));
- package.Add(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit
- package.Add(Word.ToByteArray((ushort)varCount));
- package.Add(Word.ToByteArray((ushort)(db)));
- package.Add((byte)dataType);
- int overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
- package.Add((byte)overflow);
- package.Add(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
- package.Add(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
- package.Add(Word.ToByteArray((ushort)(varCount)));
-
- // now join the header and the data
- package.Add(value);
-
- await stream.WriteAsync(package.Array, 0, package.Array.Length);
+ await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
var s7data = await COTP.TSDU.ReadAsync(stream);
if (s7data == null || s7data[14] != 0xff)
+ {
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
+ }
}
catch (Exception exc)
{
diff --git a/S7.Net/PlcSynchronous.cs b/S7.Net/PlcSynchronous.cs
index 74b02bc..9ae2cc0 100644
--- a/S7.Net/PlcSynchronous.cs
+++ b/S7.Net/PlcSynchronous.cs
@@ -1,9 +1,11 @@
using S7.Net.Types;
using System;
+using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using S7.Net.Protocol;
+using S7.Net.Helper;
//Implement synchronous methods here
namespace S7.Net
@@ -32,11 +34,16 @@ namespace S7.Net
var s7data = COTP.TSDU.Read(stream);
if (s7data == null)
throw new WrongNumberOfBytesException("No data received in response to Communication Setup");
+ if (s7data.Length < 2)
+ throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
//Check for S7 Ack Data
if (s7data[1] != 0x03)
throw new InvalidDataException("Error reading Communication Setup response", s7data, 1, 0x03);
+ if (s7data.Length < 20)
+ throw new WrongNumberOfBytesException("Not enough data received in response to Communication Setup");
+
MaxPDUSize = (short)(s7data[18] * 256 + s7data[19]);
}
catch (Exception exc)
@@ -80,20 +87,17 @@ namespace S7.Net
/// Returns the bytes in an array
public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count)
{
- List resultBytes = new List();
- int index = startByteAdr;
+ var result = new byte[count];
+ int index = 0;
while (count > 0)
{
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
- var maxToRead = (int)Math.Min(count, MaxPDUSize - 18);
- byte[] bytes = ReadBytesWithSingleRequest(dataType, db, index, maxToRead);
- if (bytes == null)
- return resultBytes.ToArray();
- resultBytes.AddRange(bytes);
+ var maxToRead = Math.Min(count, MaxPDUSize - 18);
+ ReadBytesWithSingleRequest(dataType, db, startByteAdr + index, result, index, maxToRead);
count -= maxToRead;
index += maxToRead;
}
- return resultBytes.ToArray();
+ return result;
}
///
@@ -232,7 +236,7 @@ namespace S7.Net
//Snap7 seems to choke on PDU sizes above 256 even if snap7
//replies with bigger PDU size in connection setup.
var maxToWrite = Math.Min(count, MaxPDUSize - 28);//TODO tested only when the MaxPDUSize is 480
- WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value.Skip(localIndex).Take(maxToWrite).ToArray());
+ WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite);
count -= maxToWrite;
localIndex += maxToWrite;
}
@@ -339,28 +343,25 @@ namespace S7.Net
WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult();
}
- private byte[] ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, int count)
+ private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
{
var stream = GetStreamIfAvailable();
- byte[] bytes = new byte[count];
try
{
// first create the header
- int packageSize = 31;
- ByteArray package = new ByteArray(packageSize);
- package.Add(ReadHeaderPackage());
+ int packageSize = 19 + 12; // 19 header + 12 for 1 request
+ var package = new System.IO.MemoryStream(packageSize);
+ BuildHeaderPackage(package);
// package.Add(0x02); // datenart
- package.Add(CreateReadDataRequestPackage(dataType, db, startByteAdr, count));
+ BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
- stream.Write(package.Array, 0, package.Array.Length);
+ var dataToSend = package.ToArray();
+ stream.Write(dataToSend, 0, dataToSend.Length);
var s7data = COTP.TSDU.Read(stream);
AssertReadResponse(s7data, count);
- for (int cnt = 0; cnt < count; cnt++)
- bytes[cnt] = s7data[cnt + 18];
-
- return bytes;
+ Array.Copy(s7data, 18, buffer, offset, count);
}
catch (Exception exc)
{
@@ -387,38 +388,14 @@ namespace S7.Net
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
}
- private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value)
+ private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
{
- var stream = GetStreamIfAvailable();
- int varCount = 0;
try
{
- varCount = value.Length;
- // first create the header
- int packageSize = 35 + value.Length;
- ByteArray package = new ByteArray(packageSize);
+ var stream = GetStreamIfAvailable();
+ var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
- package.Add(new byte[] { 3, 0 });
- //complete package size
- package.Add(Int.ToByteArray((short)packageSize));
- package.Add(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
- package.Add(Word.ToByteArray((ushort)(varCount - 1)));
- package.Add(new byte[] { 0, 0x0e });
- package.Add(Word.ToByteArray((ushort)(varCount + 4)));
- package.Add(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
- package.Add(Word.ToByteArray((ushort)varCount));
- package.Add(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(Word.ToByteArray((ushort)(startByteAdr * 8)));
- package.Add(new byte[] { 0, 4 });
- package.Add(Word.ToByteArray((ushort)(varCount * 8)));
-
- // now join the header and the data
- package.Add(value);
-
- stream.Write(package.Array, 0, package.Array.Length);
+ stream.Write(dataToSend, 0, dataToSend.Length);
var s7data = COTP.TSDU.Read(stream);
if (s7data == null || s7data[14] != 0xff)
@@ -432,43 +409,85 @@ namespace S7.Net
}
}
+ private byte[] BuildWriteBytesPackage(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
+ {
+ int varCount = count;
+ // first create the header
+ int packageSize = 35 + varCount;
+ var package = new MemoryStream(new byte[packageSize]);
+
+ package.WriteByte(3);
+ package.WriteByte(0);
+ //complete package size
+ package.WriteByteArray(Int.ToByteArray((short)packageSize));
+ package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
+ package.WriteByteArray(new byte[] { 0, 0x0e });
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
+ package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
+ package.WriteByteArray(Word.ToByteArray((ushort)varCount));
+ package.WriteByteArray(Word.ToByteArray((ushort)(db)));
+ package.WriteByte((byte)dataType);
+ var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
+ package.WriteByte((byte)overflow);
+ package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8)));
+ package.WriteByteArray(new byte[] { 0, 4 });
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount * 8)));
+
+ // now join the header and the data
+ package.Write(value, dataOffset, count);
+
+ return package.ToArray();
+ }
+
+ private byte[] BuildWriteBitPackage(DataType dataType, int db, int startByteAdr, bool bitValue, int bitAdr)
+ {
+ var stream = GetStreamIfAvailable();
+ var value = new[] { bitValue ? (byte)1 : (byte)0 };
+ int varCount = 1;
+ // first create the header
+ int packageSize = 35 + varCount;
+ var package = new MemoryStream(new byte[packageSize]);
+
+ package.WriteByte(3);
+ package.WriteByte(0);
+ //complete package size
+ package.WriteByteArray(Int.ToByteArray((short)packageSize));
+ package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
+ package.WriteByteArray(new byte[] { 0, 0x0e });
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
+ package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit
+ package.WriteByteArray(Word.ToByteArray((ushort)varCount));
+ package.WriteByteArray(Word.ToByteArray((ushort)(db)));
+ package.WriteByte((byte)dataType);
+ var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
+ package.WriteByte((byte)overflow);
+ package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
+ package.WriteByteArray(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
+ package.WriteByteArray(Word.ToByteArray((ushort)(varCount)));
+
+ // now join the header and the data
+ package.WriteByteArray(value);
+
+ return package.ToArray();
+ }
+
+
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
{
var stream = GetStreamIfAvailable();
- int varCount = 0;
-
try
{
- var value = new[] {bitValue ? (byte) 1 : (byte) 0};
- varCount = value.Length;
- // first create the header
- int packageSize = 35 + value.Length;
- ByteArray package = new ByteArray(packageSize);
+ var dataToSend = BuildWriteBitPackage(dataType, db, startByteAdr, bitValue, bitAdr);
- package.Add(new byte[] { 3, 0, 0 });
- package.Add((byte)packageSize);
- package.Add(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
- package.Add(Word.ToByteArray((ushort)(varCount - 1)));
- package.Add(new byte[] { 0, 0x0e });
- package.Add(Word.ToByteArray((ushort)(varCount + 4)));
- package.Add(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit
- package.Add(Word.ToByteArray((ushort)varCount));
- package.Add(Word.ToByteArray((ushort)(db)));
- package.Add((byte)dataType);
- int overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
- package.Add((byte)overflow);
- package.Add(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
- package.Add(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
- package.Add(Word.ToByteArray((ushort)(varCount)));
-
- // now join the header and the data
- package.Add(value);
-
- stream.Write(package.Array, 0, package.Array.Length);
+ stream.Write(dataToSend, 0, dataToSend.Length);
var s7data = COTP.TSDU.Read(stream);
if (s7data == null || s7data[14] != 0xff)
+ {
throw new PlcException(ErrorCode.WrongNumberReceivedBytes);
+ }
}
catch (Exception exc)
{
@@ -496,15 +515,16 @@ namespace S7.Net
{
// first create the header
int packageSize = 19 + (dataItems.Count * 12);
- ByteArray package = new ByteArray(packageSize);
- package.Add(ReadHeaderPackage(dataItems.Count));
+ var package = new System.IO.MemoryStream(packageSize);
+ BuildHeaderPackage(package, 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)));
+ BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count));
}
- stream.Write(package.Array, 0, package.Array.Length);
+ var dataToSend = package.ToArray();
+ stream.Write(dataToSend, 0, dataToSend.Length);
var s7data = COTP.TSDU.Read(stream); //TODO use Async
if (s7data == null || s7data[14] != 0xff)
diff --git a/S7.Net/Types/ByteArray.cs b/S7.Net/Types/ByteArray.cs
index 322cee8..e80e4b5 100644
--- a/S7.Net/Types/ByteArray.cs
+++ b/S7.Net/Types/ByteArray.cs
@@ -50,6 +50,11 @@ namespace S7.Net.Types
list.AddRange(items);
}
+ public void Add(IEnumerable items)
+ {
+ list.AddRange(items);
+ }
+
public void Add(ByteArray byteArray)
{
list.AddRange(byteArray.Array);