diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index bc7b024b..8116e8b7 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -75,7 +75,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Install Snap7 Linux
if: ${{ matrix.os == 'ubuntu-20.04' }}
@@ -90,14 +90,14 @@ jobs:
brew install snap7
- name: Setup Dotnet
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: |
6.x
7.x
- name: Nuget Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.nuget/packages
# Look to see if there is a cache hit for the corresponding requirements file
diff --git a/S7.Net/COTP.cs b/S7.Net/COTP.cs
index 3e5abbbb..4f8b1cd4 100644
--- a/S7.Net/COTP.cs
+++ b/S7.Net/COTP.cs
@@ -55,6 +55,7 @@ public TPDU(TPKT tPKT)
/// See: https://tools.ietf.org/html/rfc905
///
/// The socket to read from
+ /// A cancellation token that can be used to cancel the asynchronous operation.
/// COTP DPDU instance
public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken)
{
@@ -89,6 +90,7 @@ public class TSDU
/// See: https://tools.ietf.org/html/rfc905
///
/// The stream to read from
+ /// A cancellation token that can be used to cancel the asynchronous operation.
/// Data in TSDU
public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken)
{
diff --git a/S7.Net/PLCHelpers.cs b/S7.Net/PLCHelpers.cs
index c0fbd78f..ef26e875 100644
--- a/S7.Net/PLCHelpers.cs
+++ b/S7.Net/PLCHelpers.cs
@@ -12,8 +12,8 @@ public partial class Plc
///
/// Creates the header to read bytes from the PLC
///
- ///
- ///
+ /// The stream to write to.
+ /// The number of items to read.
private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount = 1)
{
//header size = 19 bytes
@@ -32,6 +32,7 @@ private static void BuildHeaderPackage(System.IO.MemoryStream stream, int amount
/// Create the bytes-package to request data from the PLC. You have to specify the memory type (dataType),
/// the address of the memory, the address of the byte and the bytes count.
///
+ /// The stream to write the read data request to.
/// MemoryType (DB, Timer, Counter, etc.)
/// Address of the memory to be read
/// Start address of the byte
diff --git a/S7.Net/PlcAsynchronous.cs b/S7.Net/PlcAsynchronous.cs
index 36fef8c6..77cd0c8b 100644
--- a/S7.Net/PlcAsynchronous.cs
+++ b/S7.Net/PlcAsynchronous.cs
@@ -428,7 +428,6 @@ public async Task WriteAsync(DataType dataType, int db, int startByteAdr, object
///
/// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
- /// If the write was not successful, check or .
///
/// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
/// Value to be written to the PLC
@@ -507,6 +506,7 @@ public async Task WriteAsync(params DataItem[] dataItems)
/// 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.
/// 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 cancellation token that can be used to cancel the asynchronous operation.
/// A task that represents the asynchronous write operation.
private async Task WriteBytesWithASingleRequestAsync(DataType dataType, int db, int startByteAdr, ReadOnlyMemory value, CancellationToken cancellationToken)
{
diff --git a/S7.Net/PlcSynchronous.cs b/S7.Net/PlcSynchronous.cs
index 4a3aaadb..afd122af 100644
--- a/S7.Net/PlcSynchronous.cs
+++ b/S7.Net/PlcSynchronous.cs
@@ -289,7 +289,6 @@ public void Write(DataType dataType, int db, int startByteAdr, object value, int
///
/// Writes a single variable from the PLC, takes in input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
- /// If the write was not successful, check or .
///
/// Input strings like "DB1.DBX0.0", "DB20.DBD200", "MB20", "T45", etc.
/// Value to be written to the PLC
diff --git a/S7.Net/S7.Net.csproj b/S7.Net/S7.Net.csproj
index bfe62f93..a5643f5d 100644
--- a/S7.Net/S7.Net.csproj
+++ b/S7.Net/S7.Net.csproj
@@ -15,12 +15,13 @@
git
PLC Siemens Communication S7
Derek Heiser 2015
- 8.0
+ latest
Enable
portable
true
snupkg
true
+ $(NoWarn);CS1591;NETSDK1138
diff --git a/S7.Net/StreamExtensions.cs b/S7.Net/StreamExtensions.cs
index 749b9150..504e4dc1 100644
--- a/S7.Net/StreamExtensions.cs
+++ b/S7.Net/StreamExtensions.cs
@@ -39,6 +39,7 @@ public static int ReadExact(this Stream stream, byte[] buffer, int offset, int c
/// the buffer to read into
/// the offset in the buffer to read into
/// the amount of bytes to read into the buffer
+ /// A cancellation token that can be used to cancel the asynchronous operation.
/// returns the amount of read bytes
public static async Task ReadExactAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
diff --git a/S7.Net/TPKT.cs b/S7.Net/TPKT.cs
index a311dcec..f24b4c06 100644
--- a/S7.Net/TPKT.cs
+++ b/S7.Net/TPKT.cs
@@ -29,6 +29,7 @@ private TPKT(byte version, byte reserved1, int length, byte[] data)
/// Reads a TPKT from the socket Async
///
/// The stream to read from
+ /// A cancellation token that can be used to cancel the asynchronous operation.
/// Task TPKT Instace
public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken)
{
diff --git a/S7.Net/Types/Class.cs b/S7.Net/Types/Class.cs
index 819b6261..be84c2b9 100644
--- a/S7.Net/Types/Class.cs
+++ b/S7.Net/Types/Class.cs
@@ -64,7 +64,8 @@ private static double GetIncreasedNumberOfBytes(double numBytes, Type type, Prop
numBytes += attribute.ReservedLengthInBytes;
break;
default:
- var propertyClass = Activator.CreateInstance(type);
+ var propertyClass = Activator.CreateInstance(type) ??
+ throw new ArgumentException($"Failed to create instance of type {type}.", nameof(type));
numBytes = GetClassSize(propertyClass, numBytes, true);
break;
}
@@ -76,6 +77,8 @@ private static double GetIncreasedNumberOfBytes(double numBytes, Type type, Prop
/// Gets the size of the class in bytes.
///
/// An instance of the class
+ /// The offset of the current field.
+ /// if this property belongs to a class being serialized as member of the class requested for serialization; otherwise, .
/// the number of bytes
public static double GetClassSize(object instance, double numBytes = 0.0, bool isInnerProperty = false)
{
@@ -84,8 +87,10 @@ public static double GetClassSize(object instance, double numBytes = 0.0, bool i
{
if (property.PropertyType.IsArray)
{
- Type elementType = property.PropertyType.GetElementType();
- Array array = (Array)property.GetValue(instance, null);
+ Type elementType = property.PropertyType.GetElementType()!;
+ Array array = (Array?) property.GetValue(instance, null) ??
+ throw new ArgumentException($"Property {property.Name} on {instance} must have a non-null value to get it's size.", nameof(instance));
+
if (array.Length <= 0)
{
throw new Exception("Cannot determine size of class, because an array is defined which has no fixed size greater than zero.");
@@ -199,7 +204,9 @@ public static double GetClassSize(object instance, double numBytes = 0.0, bool i
numBytes += sData.Length;
break;
default:
- var propClass = Activator.CreateInstance(propertyType);
+ var propClass = Activator.CreateInstance(propertyType) ??
+ throw new ArgumentException($"Failed to create instance of type {propertyType}.", nameof(propertyType));
+
numBytes = FromBytes(propClass, bytes, numBytes);
value = propClass;
break;
@@ -213,6 +220,8 @@ public static double GetClassSize(object instance, double numBytes = 0.0, bool i
///
/// The object to fill in the given array of bytes
/// The array of bytes
+ /// The offset for the current field.
+ /// if this class is the type of a member of the class to be serialized; otherwise, .
public static double FromBytes(object sourceClass, byte[] bytes, double numBytes = 0, bool isInnerClass = false)
{
if (bytes == null)
@@ -223,9 +232,11 @@ public static double FromBytes(object sourceClass, byte[] bytes, double numBytes
{
if (property.PropertyType.IsArray)
{
- Array array = (Array)property.GetValue(sourceClass, null);
+ Array array = (Array?) property.GetValue(sourceClass, null) ??
+ throw new ArgumentException($"Property {property.Name} on sourceClass must be an array instance.", nameof(sourceClass));
+
IncrementToEven(ref numBytes);
- Type elementType = property.PropertyType.GetElementType();
+ Type elementType = property.PropertyType.GetElementType()!;
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
{
array.SetValue(
@@ -320,26 +331,30 @@ private static double SetBytesFromProperty(object propertyValue, PropertyInfo? p
///
/// Creates a byte array depending on the struct type.
///
- /// The struct object
+ /// The struct object.
+ /// The target byte array.
+ /// The offset for the current field.
/// A byte array or null if fails.
public static double ToBytes(object sourceClass, byte[] bytes, double numBytes = 0.0)
{
var properties = GetAccessableProperties(sourceClass.GetType());
foreach (var property in properties)
{
+ var value = property.GetValue(sourceClass, null) ??
+ throw new ArgumentException($"Property {property.Name} on sourceClass can't be null.", nameof(sourceClass));
+
if (property.PropertyType.IsArray)
{
- Array array = (Array)property.GetValue(sourceClass, null);
+ Array array = (Array) value;
IncrementToEven(ref numBytes);
- Type elementType = property.PropertyType.GetElementType();
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
{
- numBytes = SetBytesFromProperty(array.GetValue(i), property, bytes, numBytes);
+ numBytes = SetBytesFromProperty(array.GetValue(i)!, property, bytes, numBytes);
}
}
else
{
- numBytes = SetBytesFromProperty(property.GetValue(sourceClass, null), property, bytes, numBytes);
+ numBytes = SetBytesFromProperty(value, property, bytes, numBytes);
}
}
return numBytes;
diff --git a/S7.Net/Types/DateTime.cs b/S7.Net/Types/DateTime.cs
index 9cafa676..a685a210 100644
--- a/S7.Net/Types/DateTime.cs
+++ b/S7.Net/Types/DateTime.cs
@@ -141,7 +141,7 @@ byte EncodeBcd(int value)
/// Converts an array of values to a byte array.
///
/// The DateTime values to convert.
- /// A byte array containing the S7 date time representations of .
+ /// A byte array containing the S7 date time representations of .
/// Thrown when any value of
/// is before
/// or after .
diff --git a/S7.Net/Types/S7String.cs b/S7.Net/Types/S7String.cs
index 46c4808a..d45c5349 100644
--- a/S7.Net/Types/S7String.cs
+++ b/S7.Net/Types/S7String.cs
@@ -8,17 +8,17 @@ namespace S7.Net.Types
/// An S7 String has a preceeding 2 byte header containing its capacity and length
///
public static class S7String
- {
- private static Encoding stringEncoding = Encoding.ASCII;
-
+ {
+ private static Encoding stringEncoding = Encoding.ASCII;
+
///
/// The Encoding used when serializing and deserializing S7String (Encoding.ASCII by default)
///
- /// StringEncoding must not be null
- public static Encoding StringEncoding
- {
- get => stringEncoding;
- set => stringEncoding = value ?? throw new ArgumentNullException(nameof(StringEncoding));
+ /// StringEncoding must not be null
+ public static Encoding StringEncoding
+ {
+ get => stringEncoding;
+ set => stringEncoding = value ?? throw new ArgumentNullException(nameof(StringEncoding));
}
///
@@ -58,7 +58,7 @@ public static string FromByteArray(byte[] bytes)
/// The string to convert to byte array.
/// The length (in characters) allocated in PLC for the string.
/// A containing the string header and string value with a maximum length of + 2.
- public static byte[] ToByteArray(string value, int reservedLength)
+ public static byte[] ToByteArray(string? value, int reservedLength)
{
if (value is null)
{
diff --git a/S7.Net/Types/S7WString.cs b/S7.Net/Types/S7WString.cs
index 8d8aabfc..001c7ef3 100644
--- a/S7.Net/Types/S7WString.cs
+++ b/S7.Net/Types/S7WString.cs
@@ -48,7 +48,7 @@ public static string FromByteArray(byte[] bytes)
/// The string to convert to byte array.
/// The length (in characters) allocated in PLC for the string.
/// A containing the string header and string value with a maximum length of + 4.
- public static byte[] ToByteArray(string value, int reservedLength)
+ public static byte[] ToByteArray(string? value, int reservedLength)
{
if (value is null)
{
diff --git a/S7.Net/Types/String.cs b/S7.Net/Types/String.cs
index 39176352..b0ccc190 100644
--- a/S7.Net/Types/String.cs
+++ b/S7.Net/Types/String.cs
@@ -12,13 +12,15 @@ public class String
/// The amount of bytes reserved for the in the PLC.
public static byte[] ToByteArray(string value, int reservedLength)
{
- var length = value?.Length;
- if (length > reservedLength) length = reservedLength;
var bytes = new byte[reservedLength];
+ if (value == null) return bytes;
+
+ var length = value.Length;
+ if (length == 0) return bytes;
- if (length == null || length == 0) return bytes;
+ if (length > reservedLength) length = reservedLength;
- System.Text.Encoding.ASCII.GetBytes(value, 0, length.Value, bytes, 0);
+ System.Text.Encoding.ASCII.GetBytes(value, 0, length, bytes, 0);
return bytes;
}
diff --git a/S7.Net/Types/Struct.cs b/S7.Net/Types/Struct.cs
index 1e955086..6f29447d 100644
--- a/S7.Net/Types/Struct.cs
+++ b/S7.Net/Types/Struct.cs
@@ -98,8 +98,8 @@ public static int GetStructSize(Type structType)
int bytePos = 0;
int bitPos = 0;
double numBytes = 0.0;
- object structValue = Activator.CreateInstance(structType);
-
+ object structValue = Activator.CreateInstance(structType) ??
+ throw new ArgumentException($"Failed to create an instance of the type {structType}.", nameof(structType));
var infos = structValue.GetType()
#if NETSTANDARD1_3
@@ -254,6 +254,14 @@ public static byte[] ToBytes(object structValue)
foreach (var info in infos)
{
+ static TValue GetValueOrThrow(FieldInfo fi, object structValue) where TValue : struct
+ {
+ var value = fi.GetValue(structValue) as TValue? ??
+ throw new ArgumentException($"Failed to convert value of field {fi.Name} of {structValue} to type {typeof(TValue)}");
+
+ return value;
+ }
+
bytes2 = null;
switch (info.FieldType.Name)
{
@@ -261,7 +269,7 @@ public static byte[] ToBytes(object structValue)
// get the value
bytePos = (int)Math.Floor(numBytes);
bitPos = (int)((numBytes - (double)bytePos) / 0.125);
- if ((bool)info.GetValue(structValue))
+ if (GetValueOrThrow(info, structValue))
bytes[bytePos] |= (byte)Math.Pow(2, bitPos); // is true
else
bytes[bytePos] &= (byte)(~(byte)Math.Pow(2, bitPos)); // is false
@@ -270,26 +278,26 @@ public static byte[] ToBytes(object structValue)
case "Byte":
numBytes = (int)Math.Ceiling(numBytes);
bytePos = (int)numBytes;
- bytes[bytePos] = (byte)info.GetValue(structValue);
+ bytes[bytePos] = GetValueOrThrow(info, structValue);
numBytes++;
break;
case "Int16":
- bytes2 = Int.ToByteArray((Int16)info.GetValue(structValue));
+ bytes2 = Int.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "UInt16":
- bytes2 = Word.ToByteArray((UInt16)info.GetValue(structValue));
+ bytes2 = Word.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "Int32":
- bytes2 = DInt.ToByteArray((Int32)info.GetValue(structValue));
+ bytes2 = DInt.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "UInt32":
- bytes2 = DWord.ToByteArray((UInt32)info.GetValue(structValue));
+ bytes2 = DWord.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "Single":
- bytes2 = Real.ToByteArray((float)info.GetValue(structValue));
+ bytes2 = Real.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "Double":
- bytes2 = LReal.ToByteArray((double)info.GetValue(structValue));
+ bytes2 = LReal.ToByteArray(GetValueOrThrow(info, structValue));
break;
case "String":
S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault();
@@ -298,8 +306,8 @@ public static byte[] ToBytes(object structValue)
bytes2 = attribute.Type switch
{
- S7StringType.S7String => S7String.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength),
- S7StringType.S7WString => S7WString.ToByteArray((string)info.GetValue(structValue), attribute.ReservedLength),
+ S7StringType.S7String => S7String.ToByteArray((string?)info.GetValue(structValue), attribute.ReservedLength),
+ S7StringType.S7WString => S7WString.ToByteArray((string?)info.GetValue(structValue), attribute.ReservedLength),
_ => throw new ArgumentException("Please use a valid string type for the S7StringAttribute")
};
break;