mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 14:28:25 +08:00
Use System.Memory for < .NET 5 and avoid (some) unnecessary allocations
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace S7.Net.Helper
|
namespace S7.Net.Helper
|
||||||
{
|
{
|
||||||
|
#if !NET5_0_OR_GREATER
|
||||||
internal static class MemoryStreamExtension
|
internal static class MemoryStreamExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -10,9 +14,25 @@ namespace S7.Net.Helper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stream"></param>
|
/// <param name="stream"></param>
|
||||||
/// <param name="value"></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);
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using S7.Net.Helper;
|
using S7.Net.Helper;
|
||||||
using S7.Net.Protocol.S7;
|
using S7.Net.Protocol.S7;
|
||||||
using S7.Net.Types;
|
using S7.Net.Types;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using DateTime = S7.Net.Types.DateTime;
|
using DateTime = S7.Net.Types.DateTime;
|
||||||
@@ -18,13 +17,13 @@ namespace S7.Net
|
|||||||
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
|
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
|
||||||
{
|
{
|
||||||
//header size = 19 bytes
|
//header size = 19 bytes
|
||||||
stream.WriteByteArray(new byte[] { 0x03, 0x00 });
|
stream.Write(new byte[] { 0x03, 0x00 });
|
||||||
//complete package size
|
//complete package size
|
||||||
stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
|
stream.Write(Int.ToByteArray((short)(19 + (12 * amount))));
|
||||||
stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
|
stream.Write(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
|
||||||
//data part size
|
//data part size
|
||||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(2 + (amount * 12))));
|
stream.Write(Word.ToByteArray((ushort)(2 + (amount * 12))));
|
||||||
stream.WriteByteArray(new byte[] { 0x00, 0x00, 0x04 });
|
stream.Write(new byte[] { 0x00, 0x00, 0x04 });
|
||||||
//amount of requests
|
//amount of requests
|
||||||
stream.WriteByte((byte)amount);
|
stream.WriteByte((byte)amount);
|
||||||
}
|
}
|
||||||
@@ -41,7 +40,7 @@ namespace S7.Net
|
|||||||
private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1)
|
private static void BuildReadDataRequestPackage(System.IO.MemoryStream stream, DataType dataType, int db, int startByteAdr, int count = 1)
|
||||||
{
|
{
|
||||||
//single data req = 12
|
//single data req = 12
|
||||||
stream.WriteByteArray(new byte[] { 0x12, 0x0a, 0x10 });
|
stream.Write(new byte[] { 0x12, 0x0a, 0x10 });
|
||||||
switch (dataType)
|
switch (dataType)
|
||||||
{
|
{
|
||||||
case DataType.Timer:
|
case DataType.Timer:
|
||||||
@@ -53,8 +52,8 @@ namespace S7.Net
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.WriteByteArray(Word.ToByteArray((ushort)(count)));
|
stream.Write(Word.ToByteArray((ushort)(count)));
|
||||||
stream.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
stream.Write(Word.ToByteArray((ushort)(db)));
|
||||||
stream.WriteByte((byte)dataType);
|
stream.WriteByte((byte)dataType);
|
||||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||||
stream.WriteByte((byte)overflow);
|
stream.WriteByte((byte)overflow);
|
||||||
@@ -62,10 +61,10 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
case DataType.Timer:
|
case DataType.Timer:
|
||||||
case DataType.Counter:
|
case DataType.Counter:
|
||||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)(startByteAdr)));
|
stream.Write(Word.ToByteArray((ushort)(startByteAdr)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stream.WriteByteArray(Types.Word.ToByteArray((ushort)((startByteAdr) * 8)));
|
stream.Write(Word.ToByteArray((ushort)((startByteAdr) * 8)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ namespace S7.Net
|
|||||||
MaxPDUSize = s7data[18] * 256 + s7data[19];
|
MaxPDUSize = s7data[18] * 256 + s7data[19];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -110,20 +109,12 @@ namespace S7.Net
|
|||||||
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default)
|
public async Task<byte[]> ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var resultBytes = new byte[count];
|
var resultBytes = new byte[count];
|
||||||
int index = 0;
|
|
||||||
while (count > 0)
|
await ReadBytesAsync(resultBytes, dataType, db, startByteAdr, cancellationToken).ConfigureAwait(false);
|
||||||
{
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
return resultBytes;
|
return resultBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -148,8 +139,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read and decode a certain number of bytes of the "VarType" provided.
|
/// 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).
|
/// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||||
@@ -323,7 +312,6 @@ namespace S7.Net
|
|||||||
return dataItems;
|
return dataItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the write was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -335,21 +323,11 @@ namespace S7.Net
|
|||||||
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is None.
|
/// <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>
|
/// 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>
|
/// <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;
|
return WriteBytesAsync(dataType, db, startByteAdr, value.AsMemory(), cancellationToken);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the write was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -373,8 +351,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a single bit from a DB with the specified index.
|
/// Write a single bit from a DB with the specified index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -496,18 +472,6 @@ namespace S7.Net
|
|||||||
await WriteBytesAsync(DataType.DataBlock, db, startByteAdr, bytes, cancellationToken).ConfigureAwait(false);
|
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)
|
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) });
|
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, buffer.Length) });
|
||||||
@@ -518,8 +482,6 @@ namespace S7.Net
|
|||||||
s7data.AsSpan(18, buffer.Length).CopyTo(buffer.Span);
|
s7data.AsSpan(18, buffer.Length).CopyTo(buffer.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
||||||
/// or when the PLC reports errors for item(s) written.
|
/// or when the PLC reports errors for item(s) written.
|
||||||
@@ -538,35 +500,6 @@ namespace S7.Net
|
|||||||
S7WriteMultiple.ParseResponse(response, response.Length, 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>
|
/// <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.
|
/// 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>
|
/// </summary>
|
||||||
@@ -594,8 +527,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
|
private async Task WriteBitWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -39,20 +39,12 @@ namespace S7.Net
|
|||||||
public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count)
|
public byte[] ReadBytes(DataType dataType, int db, int startByteAdr, int count)
|
||||||
{
|
{
|
||||||
var result = new byte[count];
|
var result = new byte[count];
|
||||||
int index = 0;
|
|
||||||
while (count > 0)
|
ReadBytes(result, dataType, db, startByteAdr);
|
||||||
{
|
|
||||||
//This works up to MaxPDUSize-1 on SNAP7. But not MaxPDUSize-0.
|
|
||||||
var maxToRead = Math.Min(count, MaxPDUSize - 18);
|
|
||||||
ReadBytesWithSingleRequest(dataType, db, startByteAdr + index, result, index, maxToRead);
|
|
||||||
count -= maxToRead;
|
|
||||||
index += maxToRead;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the read was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -75,8 +67,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read and decode a certain number of bytes of the "VarType" provided.
|
/// 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).
|
/// This can be used to read multiple consecutive variables of the same type (Word, DWord, Int, etc).
|
||||||
@@ -137,7 +127,6 @@ namespace S7.Net
|
|||||||
return ReadStruct(typeof(T), db, startByteAdr) as T?;
|
return ReadStruct(typeof(T), db, startByteAdr) as T?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
/// Reads all the bytes needed to fill a class in C#, starting from a certain address, and set all the properties values to the value that are read from the PLC.
|
||||||
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
/// This reads only properties, it doesn't read private variable or public variable without {get;set;} specified.
|
||||||
@@ -205,22 +194,9 @@ namespace S7.Net
|
|||||||
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
/// <param name="value">Bytes to write. If more than 200, multiple requests will be made.</param>
|
||||||
public void WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value)
|
public void WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value)
|
||||||
{
|
{
|
||||||
int localIndex = 0;
|
WriteBytes(dataType, db, startByteAdr, value.AsSpan());
|
||||||
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 = Math.Min(count, MaxPDUSize - 28);//TODO tested only when the MaxPDUSize is 480
|
|
||||||
WriteBytesWithASingleRequest(dataType, db, startByteAdr + localIndex, value, localIndex, maxToWrite);
|
|
||||||
count -= maxToWrite;
|
|
||||||
localIndex += maxToWrite;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a number of bytes from a DB starting from a specified index. This handles more than 200 bytes with multiple requests.
|
/// 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.
|
/// If the write was not successful, check LastErrorCode or LastErrorString.
|
||||||
@@ -244,8 +220,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write a single bit from a DB with the specified index.
|
/// Write a single bit from a DB with the specified index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -347,43 +321,18 @@ namespace S7.Net
|
|||||||
WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult();
|
WriteClassAsync(classValue, db, startByteAdr).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// first create the header
|
|
||||||
int packageSize = 19 + 12; // 19 header + 12 for 1 request
|
|
||||||
var package = new System.IO.MemoryStream(packageSize);
|
|
||||||
BuildHeaderPackage(package);
|
|
||||||
// package.Add(0x02); // datenart
|
|
||||||
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, count);
|
|
||||||
|
|
||||||
var dataToSend = package.ToArray();
|
|
||||||
var s7data = RequestTsdu(dataToSend);
|
|
||||||
AssertReadResponse(s7data, count);
|
|
||||||
|
|
||||||
Array.Copy(s7data, 18, buffer, offset, count);
|
|
||||||
}
|
|
||||||
catch (Exception exc)
|
|
||||||
{
|
|
||||||
throw new PlcException(ErrorCode.ReadData, exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, Span<byte> buffer)
|
private void ReadBytesWithSingleRequest(DataType dataType, int db, int startByteAdr, Span<byte> buffer)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// first create the header
|
// first create the header
|
||||||
int packageSize = 19 + 12; // 19 header + 12 for 1 request
|
const int packageSize = 19 + 12; // 19 header + 12 for 1 request
|
||||||
var package = new System.IO.MemoryStream(packageSize);
|
var dataToSend = new byte[packageSize];
|
||||||
|
var package = new MemoryStream(dataToSend);
|
||||||
BuildHeaderPackage(package);
|
BuildHeaderPackage(package);
|
||||||
// package.Add(0x02); // datenart
|
// package.Add(0x02); // datenart
|
||||||
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, buffer.Length);
|
BuildReadDataRequestPackage(package, dataType, db, startByteAdr, buffer.Length);
|
||||||
|
|
||||||
var dataToSend = package.ToArray();
|
|
||||||
var s7data = RequestTsdu(dataToSend);
|
var s7data = RequestTsdu(dataToSend);
|
||||||
AssertReadResponse(s7data, buffer.Length);
|
AssertReadResponse(s7data, buffer.Length);
|
||||||
|
|
||||||
@@ -395,8 +344,6 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
/// Write DataItem(s) to the PLC. Throws an exception if the response is invalid
|
||||||
/// or when the PLC reports errors for item(s) written.
|
/// or when the PLC reports errors for item(s) written.
|
||||||
@@ -406,7 +353,6 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
AssertPduSizeForWrite(dataItems);
|
AssertPduSizeForWrite(dataItems);
|
||||||
|
|
||||||
|
|
||||||
var message = new ByteArray();
|
var message = new ByteArray();
|
||||||
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
var length = S7WriteMultiple.CreateRequest(message, dataItems);
|
||||||
var response = RequestTsdu(message.Array, 0, length);
|
var response = RequestTsdu(message.Array, 0, length);
|
||||||
@@ -414,23 +360,6 @@ namespace S7.Net
|
|||||||
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
S7WriteMultiple.ParseResponse(response, response.Length, dataItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, byte[] value, int dataOffset, int count)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dataToSend = BuildWriteBytesPackage(dataType, db, startByteAdr, value, dataOffset, count);
|
|
||||||
var s7data = RequestTsdu(dataToSend);
|
|
||||||
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
|
||||||
}
|
|
||||||
catch (Exception exc)
|
|
||||||
{
|
|
||||||
throw new PlcException(ErrorCode.WriteData, exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, ReadOnlySpan<byte> value)
|
private void WriteBytesWithASingleRequest(DataType dataType, int db, int startByteAdr, ReadOnlySpan<byte> value)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -446,107 +375,72 @@ namespace S7.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
|
||||||
|
|
||||||
private byte[] BuildWriteBytesPackage(DataType dataType, int db, int startByteAdr, ReadOnlySpan<byte> value)
|
private byte[] BuildWriteBytesPackage(DataType dataType, int db, int startByteAdr, ReadOnlySpan<byte> value)
|
||||||
{
|
{
|
||||||
int varCount = value.Length;
|
int varCount = value.Length;
|
||||||
// first create the header
|
// first create the header
|
||||||
int packageSize = 35 + varCount;
|
int packageSize = 35 + varCount;
|
||||||
var package = new MemoryStream(new byte[packageSize]);
|
var packageData = new byte[packageSize];
|
||||||
|
var package = new MemoryStream(packageData);
|
||||||
|
|
||||||
package.WriteByte(3);
|
package.WriteByte(3);
|
||||||
package.WriteByte(0);
|
package.WriteByte(0);
|
||||||
//complete package size
|
//complete package size
|
||||||
package.WriteByteArray(Int.ToByteArray((short)packageSize));
|
package.Write(Int.ToByteArray((short)packageSize));
|
||||||
package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
// This overload doesn't allocate the byte array, it refers to assembly's static data segment
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
|
package.Write(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
||||||
package.WriteByteArray(new byte[] { 0, 0x0e });
|
package.Write(Word.ToByteArray((ushort)(varCount - 1)));
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
|
package.Write(new byte[] { 0, 0x0e });
|
||||||
package.WriteByteArray(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
|
package.Write(Word.ToByteArray((ushort)(varCount + 4)));
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)varCount));
|
package.Write(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x02 });
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
package.Write(Word.ToByteArray((ushort)varCount));
|
||||||
|
package.Write(Word.ToByteArray((ushort)(db)));
|
||||||
package.WriteByte((byte)dataType);
|
package.WriteByte((byte)dataType);
|
||||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||||
package.WriteByte((byte)overflow);
|
package.WriteByte((byte)overflow);
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8)));
|
package.Write(Word.ToByteArray((ushort)(startByteAdr * 8)));
|
||||||
package.WriteByteArray(new byte[] { 0, 4 });
|
package.Write(new byte[] { 0, 4 });
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount * 8)));
|
package.Write(Word.ToByteArray((ushort)(varCount * 8)));
|
||||||
|
|
||||||
// now join the header and the data
|
// now join the header and the data
|
||||||
package.Write(value);
|
package.Write(value);
|
||||||
|
|
||||||
return package.ToArray();
|
return packageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private byte[] BuildWriteBitPackage(DataType dataType, int db, int startByteAdr, bool bitValue, int bitAdr)
|
private byte[] BuildWriteBitPackage(DataType dataType, int db, int startByteAdr, bool bitValue, int bitAdr)
|
||||||
{
|
{
|
||||||
var value = new[] { bitValue ? (byte)1 : (byte)0 };
|
var value = new[] { bitValue ? (byte)1 : (byte)0 };
|
||||||
int varCount = 1;
|
int varCount = 1;
|
||||||
// first create the header
|
// first create the header
|
||||||
int packageSize = 35 + varCount;
|
int packageSize = 35 + varCount;
|
||||||
var package = new MemoryStream(new byte[packageSize]);
|
var packageData = new byte[packageSize];
|
||||||
|
var package = new MemoryStream(packageData);
|
||||||
|
|
||||||
package.WriteByte(3);
|
package.WriteByte(3);
|
||||||
package.WriteByte(0);
|
package.WriteByte(0);
|
||||||
//complete package size
|
//complete package size
|
||||||
package.WriteByteArray(Int.ToByteArray((short)packageSize));
|
package.Write(Int.ToByteArray((short)packageSize));
|
||||||
package.WriteByteArray(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
package.Write(new byte[] { 2, 0xf0, 0x80, 0x32, 1, 0, 0 });
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount - 1)));
|
package.Write(Word.ToByteArray((ushort)(varCount - 1)));
|
||||||
package.WriteByteArray(new byte[] { 0, 0x0e });
|
package.Write(new byte[] { 0, 0x0e });
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount + 4)));
|
package.Write(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.Write(new byte[] { 0x05, 0x01, 0x12, 0x0a, 0x10, 0x01 }); //ending 0x01 is used for writing a sinlge bit
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)varCount));
|
package.Write(Word.ToByteArray((ushort)varCount));
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(db)));
|
package.Write(Word.ToByteArray((ushort)(db)));
|
||||||
package.WriteByte((byte)dataType);
|
package.WriteByte((byte)dataType);
|
||||||
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
var overflow = (int)(startByteAdr * 8 / 0xffffU); // handles words with address bigger than 8191
|
||||||
package.WriteByte((byte)overflow);
|
package.WriteByte((byte)overflow);
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
|
package.Write(Word.ToByteArray((ushort)(startByteAdr * 8 + bitAdr)));
|
||||||
package.WriteByteArray(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
|
package.Write(new byte[] { 0, 0x03 }); //ending 0x03 is used for writing a sinlge bit
|
||||||
package.WriteByteArray(Word.ToByteArray((ushort)(varCount)));
|
package.Write(Word.ToByteArray((ushort)(varCount)));
|
||||||
|
|
||||||
// now join the header and the data
|
// now join the header and the data
|
||||||
package.WriteByteArray(value);
|
package.Write(value);
|
||||||
|
|
||||||
return package.ToArray();
|
return packageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
private void WriteBitWithASingleRequest(DataType dataType, int db, int startByteAdr, int bitAdr, bool bitValue)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -578,7 +472,8 @@ namespace S7.Net
|
|||||||
{
|
{
|
||||||
// first create the header
|
// first create the header
|
||||||
int packageSize = 19 + (dataItems.Count * 12);
|
int packageSize = 19 + (dataItems.Count * 12);
|
||||||
var package = new System.IO.MemoryStream(packageSize);
|
var dataToSend = new byte[packageSize];
|
||||||
|
var package = new MemoryStream(dataToSend);
|
||||||
BuildHeaderPackage(package, dataItems.Count);
|
BuildHeaderPackage(package, dataItems.Count);
|
||||||
// package.Add(0x02); // datenart
|
// package.Add(0x02); // datenart
|
||||||
foreach (var dataItem in dataItems)
|
foreach (var dataItem in dataItems)
|
||||||
@@ -586,8 +481,7 @@ namespace S7.Net
|
|||||||
BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count));
|
BuildReadDataRequestPackage(package, dataItem.DataType, dataItem.DB, dataItem.StartByteAdr, VarTypeToByteLength(dataItem.VarType, dataItem.Count));
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataToSend = package.ToArray();
|
byte[] s7data = RequestTsdu(dataToSend);
|
||||||
var s7data = RequestTsdu(dataToSend);
|
|
||||||
|
|
||||||
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
ValidateResponseCode((ReadWriteErrorCode)s7data[14]);
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,10 @@
|
|||||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net452' Or '$(TargetFramework)' == 'netstandard2.0' ">
|
<PropertyGroup Condition="'$(TargetFramework)' == 'net452' Or '$(TargetFramework)' == 'netstandard2.0' ">
|
||||||
<DefineConstants>NET_FULL</DefineConstants>
|
<DefineConstants>NET_FULL</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' != 'net5.0'">
|
||||||
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
|
|||||||
Reference in New Issue
Block a user