Skip to content

Commit bc7c27e

Browse files
committed
Release S7NetPlus 0.18.0
Release highlights: - Add Memory/Span support from 0.17.0 to < net5 targets
2 parents 2fc9eaa + f0256fd commit bc7c27e

File tree

5 files changed

+81
-233
lines changed

5 files changed

+81
-233
lines changed
Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-

1+
using System;
2+
using System.Buffers;
3+
using System.IO;
4+
25
namespace S7.Net.Helper
36
{
7+
#if !NET5_0_OR_GREATER
48
internal static class MemoryStreamExtension
59
{
610
/// <summary>
@@ -10,9 +14,25 @@ internal static class MemoryStreamExtension
1014
/// </summary>
1115
/// <param name="stream"></param>
1216
/// <param name="value"></param>
13-
public static void WriteByteArray(this System.IO.MemoryStream stream, byte[] value)
17+
public static void Write(this MemoryStream stream, byte[] value)
1418
{
1519
stream.Write(value, 0, value.Length);
1620
}
21+
22+
/// <summary>
23+
/// Helper function to write the whole content of the given byte span to a memory stream.
24+
/// </summary>
25+
/// <param name="stream"></param>
26+
/// <param name="value"></param>
27+
public static void Write(this MemoryStream stream, ReadOnlySpan<byte> value)
28+
{
29+
byte[] buffer = ArrayPool<byte>.Shared.Rent(value.Length);
30+
31+
value.CopyTo(buffer);
32+
stream.Write(buffer, 0, value.Length);
33+
34+
ArrayPool<byte>.Shared.Return(buffer);
35+
}
1736
}
37+
#endif
1838
}

S7.Net/PLCHelpers.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using S7.Net.Helper;
22
using S7.Net.Protocol.S7;
33
using S7.Net.Types;
4-
using System;
54
using System.Collections.Generic;
65
using System.Linq;
76
using DateTime = S7.Net.Types.DateTime;
@@ -18,13 +17,13 @@ public partial class Plc
1817
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
1918
{
2019
//header size = 19 bytes
21-
stream.WriteByteArray(new byte[] { 0x03, 0x00 });
20+
stream.Write(new byte[] { 0x03, 0x00 });
2221
//complete package size
23-
stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
24-
stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
22+
stream.Write(Int.ToByteArray((short)(19 + (12 * amount))));
23+
stream.Write(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
2524
//data part size
26-
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12))));
27-
stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 });
25+
stream.Write(Word.ToByteArray((ushort)(2 + (amount * 12))));
26+
stream.Write(new byte[] { 0x00, 0x00, 0x04 });
2827
//amount of requests
2928
stream.WriteByte((byte)amount);
3029
}
@@ -41,7 +40,7 @@ private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount
4140
private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1)
4241
{
4342
//single data req = 12
44-
stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 });
43+
stream.Write(new byte[] { 0x12, 0x0a, 0x10 });
4544
switch (dataType)
4645
{
4746
case DataType.Timer:
@@ -53,19 +52,19 @@ private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, D
5352
break;
5453
}
5554

56-
stream.WriteByteArray(Word.ToByteArray((ushort)(count)));
57-
stream.WriteByteArray(Word.ToByteArray((ushort)(db)));
55+
stream.Write(Word.ToByteArray((ushort)(count)));
56+
stream.Write(Word.ToByteArray((ushort)(db)));
5857
stream.WriteByte((byte)dataType);
5958
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
6059
stream.WriteByte((byte)overflow);
6160
switch (dataType)
6261
{
6362
case DataType.Timer:
6463
case DataType.Counter:
65-
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr)));
64+
stream.Write(Word.ToByteArray((ushort)(startByteAdr)));
6665
break;
6766
default:
68-
stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
67+
stream.Write(Word.ToByteArray((ushort)((startByteAdr) * 8)));
6968
break;
7069
}
7170
}

S7.Net/PlcAsynchronous.cs

Lines changed: 5 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ private async Task SetupConnection(Stream stream, CancellationToken cancellation
9595
MaxPDUSize = s7data[18] * 256 + s7data[19];
9696
}
9797

98-
9998
/// <summary>
10099
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
101100
/// If the read was not successful, check LastErrorCode or LastErrorString.
@@ -110,20 +109,12 @@ private async Task SetupConnection(Stream stream, CancellationToken cancellation
110109
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default)
111110
{
112111
var resultBytes = new byte[count];
113-
int index = 0;
114-
while (count > 0)
115-
{
116-
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
117-
var maxToRead = Math.Min(count, MaxPDUSize - 18);
118-
await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken).ConfigureAwait(false);
119-
count -= maxToRead;
120-
index += maxToRead;
121-
}
112+
113+
await ReadBytesAsync(resultBytes, dataType, db, startByteAdr, cancellationToken).ConfigureAwait(false);
114+
122115
return resultBytes;
123116
}
124117

125-
#if NET5_0_OR_GREATER
126-
127118
/// <summary>
128119
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
129120
/// If the read was not successful, check LastErrorCode or LastErrorString.
@@ -148,8 +139,6 @@ public async Task ReadBytesAsync(Memory<byte> buffer, DataType dataType, int db,
148139
}
149140
}
150141

151-
#endif
152-
153142
/// <summary>
154143
/// Read and decode a certain number of bytes of the "VarType" provided.
155144
/// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
@@ -323,7 +312,6 @@ public async Task<List<DataItem>> ReadMultipleVarsAsync(List<DataItem> dataItems
323312
return dataItems;
324313
}
325314

326-
327315
/// <summary>
328316
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
329317
/// If the write was not successful, check LastErrorCode or LastErrorString.
@@ -335,21 +323,11 @@ public async Task<List<DataItem>> ReadMultipleVarsAsync(List<DataItem> dataItems
335323
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
336324
/// Please note that cancellation is advisory/cooperative and will not lead to immediate cancellation in all cases.</param>
337325
/// <returns>A task that represents the asynchronous write operation.</returns>
338-
public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken cancellationToken = default)
326+
public Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken cancellationToken = default)
339327
{
340-
int localIndex = 0;
341-
int count = value.Length;
342-
while (count > 0)
343-
{
344-
var maxToWrite = (int)Math.Min(count, MaxPDUSize - 35);
345-
await WriteBytesWithASingleRequestAsync(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite, cancellationToken).ConfigureAwait(false);
346-
count -= maxToWrite;
347-
localIndex += maxToWrite;
348-
}
328+
return WriteBytesAsync(dataType, db, startByteAdr, value.AsMemory(), cancellationToken);
349329
}
350330

351-
#if NET5_0_OR_GREATER
352-
353331
/// <summary>
354332
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
355333
/// If the write was not successful, check LastErrorCode or LastErrorString.
@@ -373,8 +351,6 @@ public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, R
373351
}
374352
}
375353

376-
#endif
377-
378354
/// <summary>
379355
/// Write a single bit from a DB with the specified index.
380356
/// </summary>
@@ -496,18 +472,6 @@ public async Task WriteClassAsync(object classValue, int db, int startByteAdr =
496472
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false);
497473
}
498474

499-
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
500-
{
501-
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, count) });
502-
503-
var s7data = await RequestTsduAsync(dataToSend, cancellationToken);
504-
AssertReadResponse(s7data, count);
505-
506-
Array.Copy(s7data, 18, buffer, offset, count);
507-
}
508-
509-
#if NET5_0_OR_GREATER
510-
511475
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, Memory<byte> buffer, CancellationToken cancellationToken)
512476
{
513477
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, buffer.Length) });
@@ -518,8 +482,6 @@ private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, in
518482
s7data.AsSpan(18, buffer.Length).CopyTo(buffer.Span);
519483
}
520484

521-
#endif
522-
523485
/// <summary>
524486
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
525487
/// or when the PLC reports errors for item(s) written.
@@ -538,35 +500,6 @@ public async Task WriteAsync(params DataItem[] dataItems)
538500
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
539501
}
540502

541-
/// <summary>
542-
/// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count.
543-
/// </summary>
544-
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
545-
/// <param name="db">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.</param>
546-
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
547-
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
548-
/// <returns>A task that represents the asynchronous write operation.</returns>
549-
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken)
550-
{
551-
try
552-
{
553-
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
554-
var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false);
555-
556-
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
557-
}
558-
catch (OperationCanceledException)
559-
{
560-
throw;
561-
}
562-
catch (Exception exc)
563-
{
564-
throw new PlcException(ErrorCode.WriteData, exc);
565-
}
566-
}
567-
568-
#if NET5_0_OR_GREATER
569-
570503
/// <summary>
571504
/// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count.
572505
/// </summary>
@@ -594,8 +527,6 @@ private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db,
594527
}
595528
}
596529

597-
#endif
598-
599530
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
600531
{
601532
try

0 commit comments

Comments
 (0)