Skip to content

Commit

Permalink
Release S7NetPlus 0.18.0
Browse files Browse the repository at this point in the history
Release highlights:
- Add Memory/Span support from 0.17.0 to < net5 targets
  • Loading branch information
mycroes committed May 30, 2023
2 parents 2fc9eaa + f0256fd commit bc7c27e
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 233 deletions.
24 changes: 22 additions & 2 deletions S7.Net/Helper/MemoryStreamExtension.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

using System;
using System.Buffers;
using System.IO;

namespace S7.Net.Helper
{
#if !NET5_0_OR_GREATER
internal static class MemoryStreamExtension
{
/// <summary>
Expand All @@ -10,9 +14,25 @@ internal static class MemoryStreamExtension
/// </summary>
/// <param name="stream"></param>
/// <param name="value"></param>
public static void WriteByteArray(this System.IO.MemoryStream stream, byte[] value)
public static void Write(this MemoryStream stream, byte[] value)
{
stream.Write(value, 0, value.Length);
}

/// <summary>
/// Helper function to write the whole content of the given byte span to a memory stream.
/// </summary>
/// <param name="stream"></param>
/// <param name="value"></param>
public static void Write(this MemoryStream stream, ReadOnlySpan<byte> value)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(value.Length);

value.CopyTo(buffer);
stream.Write(buffer, 0, value.Length);

ArrayPool<byte>.Shared.Return(buffer);
}
}
#endif
}
21 changes: 10 additions & 11 deletions S7.Net/PLCHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using S7.Net.Helper;
using S7.Net.Protocol.S7;
using S7.Net.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using DateTime = S7.Net.Types.DateTime;
Expand All @@ -18,13 +17,13 @@ public partial class Plc
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
{
//header size = 19 bytes
stream.WriteByteArray(new byte[] { 0x03, 0x00 });
stream.Write(new byte[] { 0x03, 0x00 });
//complete package size
stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
stream.Write(Int.ToByteArray((short)(19 + (12 * amount))));
stream.Write(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
//data part size
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12))));
stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 });
stream.Write(Word.ToByteArray((ushort)(2 + (amount * 12))));
stream.Write(new byte[] { 0x00, 0x00, 0x04 });
//amount of requests
stream.WriteByte((byte)amount);
}
Expand All @@ -41,7 +40,7 @@ private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount
private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1)
{
//single data req = 12
stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 });
stream.Write(new byte[] { 0x12, 0x0a, 0x10 });
switch (dataType)
{
case DataType.Timer:
Expand All @@ -53,19 +52,19 @@ private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, D
break;
}

stream.WriteByteArray(Word.ToByteArray((ushort)(count)));
stream.WriteByteArray(Word.ToByteArray((ushort)(db)));
stream.Write(Word.ToByteArray((ushort)(count)));
stream.Write(Word.ToByteArray((ushort)(db)));
stream.WriteByte((byte)dataType);
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
stream.WriteByte((byte)overflow);
switch (dataType)
{
case DataType.Timer:
case DataType.Counter:
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr)));
stream.Write(Word.ToByteArray((ushort)(startByteAdr)));
break;
default:
stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
stream.Write(Word.ToByteArray((ushort)((startByteAdr) * 8)));
break;
}
}
Expand Down
79 changes: 5 additions & 74 deletions S7.Net/PlcAsynchronous.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ private async Task SetupConnection(Stream stream, CancellationToken cancellation
MaxPDUSize = s7data[18] * 256 + s7data[19];
}


/// <summary>
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
/// If the read was not successful, check LastErrorCode or LastErrorString.
Expand All @@ -110,20 +109,12 @@ private async Task SetupConnection(Stream stream, CancellationToken cancellation
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default)
{
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 = Math.Min(count, MaxPDUSize - 18);
await ReadBytesWithSingleRequestAsync(dataType, db, startByteAdr + index, resultBytes, index, maxToRead, cancellationToken).ConfigureAwait(false);
count -= maxToRead;
index += maxToRead;
}

await ReadBytesAsync(resultBytes, dataType, db, startByteAdr, cancellationToken).ConfigureAwait(false);

return resultBytes;
}

#if NET5_0_OR_GREATER

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

#endif

/// <summary>
/// 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).
Expand Down Expand Up @@ -323,7 +312,6 @@ public async Task<List<DataItem>> ReadMultipleVarsAsync(List<DataItem> dataItems
return dataItems;
}


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

#if NET5_0_OR_GREATER

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

#endif

/// <summary>
/// Write a single bit from a DB with the specified index.
/// </summary>
Expand Down Expand Up @@ -496,18 +472,6 @@ public async Task WriteClassAsync(object classValue, int db, int startByteAdr =
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false);
}

private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, count) });

var s7data = await RequestTsduAsync(dataToSend, cancellationToken);
AssertReadResponse(s7data, count);

Array.Copy(s7data, 18, buffer, offset, count);
}

#if NET5_0_OR_GREATER

private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, Memory<byte> buffer, CancellationToken cancellationToken)
{
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, buffer.Length) });
Expand All @@ -518,8 +482,6 @@ private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, in
s7data.AsSpan(18, buffer.Length).CopyTo(buffer.Span);
}

#endif

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

/// <summary>
/// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count.
/// </summary>
/// <param name="dataType">Data type of the memory area, can be DB, Timer, Counter, Merker(Memory), Input, Output.</param>
/// <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>
/// <param name="startByteAdr">Start byte address. If you want to read DB1.DBW200, this is 200.</param>
/// <param name="value">Bytes to write. The lenght of this parameter can't be higher than 200. If you need more, use recursion.</param>
/// <returns>A task that represents the asynchronous write operation.</returns>
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count, CancellationToken cancellationToken)
{
try
{
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
var s7data = await RequestTsduAsync(dataToSend, cancellationToken).ConfigureAwait(false);

ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exc)
{
throw new PlcException(ErrorCode.WriteData, exc);
}
}

#if NET5_0_OR_GREATER

/// <summary>
/// Writes up to 200 bytes to the PLC. You must specify the memory area type, memory are address, byte start address and bytes count.
/// </summary>
Expand Down Expand Up @@ -594,8 +527,6 @@ private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db,
}
}

#endif

private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
{
try
Expand Down
Loading

0 comments on commit bc7c27e

Please sign in to comment.