diff --git a/S7.Net.UnitTest/Helpers/TestStruct.cs b/S7.Net.UnitTest/Helpers/TestStruct.cs
index c40c6f4..f07688a 100644
--- a/S7.Net.UnitTest/Helpers/TestStruct.cs
+++ b/S7.Net.UnitTest/Helpers/TestStruct.cs
@@ -1,4 +1,5 @@
-
+using S7.Net.Types;
+
namespace S7.Net.UnitTest.Helpers
{
public struct TestStruct
@@ -7,6 +8,7 @@ namespace S7.Net.UnitTest.Helpers
/// DB1.DBX0.0
///
public bool BitVariable00;
+
public bool BitVariable01;
public bool BitVariable02;
public bool BitVariable03;
@@ -19,6 +21,7 @@ namespace S7.Net.UnitTest.Helpers
/// DB1.DBX1.0
///
public bool BitVariable10;
+
public bool BitVariable11;
public bool BitVariable12;
public bool BitVariable13;
@@ -51,5 +54,17 @@ namespace S7.Net.UnitTest.Helpers
/// DB1.DBD16
///
public ushort DWordVariable;
+
+ ///
+ /// DB1.DBX20.0
+ ///
+ [S7String(S7StringType.S7WString, 10)]
+ public string WStringVariable;
+
+ ///
+ /// DB1.DBX44.0
+ ///
+ [S7String(S7StringType.S7String, 10)]
+ public string StringVariable;
}
}
diff --git a/S7.Net.UnitTest/S7NetTestsAsync.cs b/S7.Net.UnitTest/S7NetTestsAsync.cs
index f90f250..cb63660 100644
--- a/S7.Net.UnitTest/S7NetTestsAsync.cs
+++ b/S7.Net.UnitTest/S7NetTestsAsync.cs
@@ -211,7 +211,9 @@ namespace S7.Net.UnitTest
IntVariable = -15000,
LRealVariable = -154.789,
RealVariable = -154.789f,
- DWordVariable = 850
+ DWordVariable = 850,
+ WStringVariable = "ÄÜÉÊéà",
+ StringVariable = "Hallo"
};
plc.WriteStruct(tc, DB2);
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
@@ -223,6 +225,8 @@ namespace S7.Net.UnitTest
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
+ Assert.AreEqual(tc.WStringVariable, tc2.WStringVariable);
+ Assert.AreEqual(tc.StringVariable, tc2.StringVariable);
}
///
@@ -739,7 +743,9 @@ namespace S7.Net.UnitTest
IntVariable = -15000,
LRealVariable = -154.789,
RealVariable = -154.789f,
- DWordVariable = 850
+ DWordVariable = 850,
+ WStringVariable = "ÄÜÉÊéà",
+ StringVariable = "Hallo"
};
plc.WriteStruct(ts, DB2);
@@ -756,6 +762,8 @@ namespace S7.Net.UnitTest
Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable);
Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable);
Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable);
+ Assert.AreEqual(ts2.WStringVariable, ts2Generic.WStringVariable);
+ Assert.AreEqual(ts2.StringVariable, ts2Generic.StringVariable);
}
[TestMethod]
diff --git a/S7.Net.UnitTest/S7NetTestsSync.cs b/S7.Net.UnitTest/S7NetTestsSync.cs
index 162c5a2..377506b 100644
--- a/S7.Net.UnitTest/S7NetTestsSync.cs
+++ b/S7.Net.UnitTest/S7NetTestsSync.cs
@@ -212,6 +212,9 @@ namespace S7.Net.UnitTest
tc.LRealVariable = -154.789;
tc.RealVariable = -154.789f;
tc.DWordVariable = 850;
+ tc.WStringVariable = "ÄÜÉÊéà";
+ tc.StringVariable = "Hallo";
+
plc.WriteStruct(tc, DB2);
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
TestStruct tc2 = (TestStruct)plc.ReadStruct(typeof(TestStruct), DB2);
@@ -222,6 +225,8 @@ namespace S7.Net.UnitTest
Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable);
Assert.AreEqual(tc.RealVariable, tc2.RealVariable);
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
+ Assert.AreEqual(tc.WStringVariable, tc2.WStringVariable);
+ Assert.AreEqual(tc.StringVariable, tc2.StringVariable);
}
///
@@ -783,6 +788,8 @@ namespace S7.Net.UnitTest
ts.LRealVariable = -154.789;
ts.RealVariable = -154.789f;
ts.DWordVariable = 850;
+ ts.WStringVariable = "ÄÜÉÊéà";
+ ts.StringVariable = "Hallo";
plc.WriteStruct(ts, DB2);
@@ -797,6 +804,8 @@ namespace S7.Net.UnitTest
Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable);
Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable);
Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable);
+ Assert.AreEqual(ts2.WStringVariable, ts2Generic.WStringVariable);
+ Assert.AreEqual(ts2.StringVariable, ts2Generic.StringVariable);
}
[TestMethod, ExpectedException(typeof(PlcException))]
diff --git a/S7.Net.UnitTest/TypeTests/S7StringTests.cs b/S7.Net.UnitTest/TypeTests/S7StringTests.cs
index 0bc8ef9..e1cdc91 100644
--- a/S7.Net.UnitTest/TypeTests/S7StringTests.cs
+++ b/S7.Net.UnitTest/TypeTests/S7StringTests.cs
@@ -100,7 +100,7 @@ namespace S7.Net.UnitTest.TypeTests
}
[TestMethod]
- public void WriteAbcWithStringLargetThanReservedLength()
+ public void WriteAbcWithStringLargerThanReservedLength()
{
Assert.ThrowsException(() => S7String.ToByteArray("Abc", 2));
}
diff --git a/S7.Net.UnitTest/TypeTests/S7WStringTests.cs b/S7.Net.UnitTest/TypeTests/S7WStringTests.cs
new file mode 100644
index 0000000..877777c
--- /dev/null
+++ b/S7.Net.UnitTest/TypeTests/S7WStringTests.cs
@@ -0,0 +1,134 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using S7.Net.Types;
+using System;
+
+namespace S7.Net.UnitTest.TypeTests
+{
+ [TestClass]
+ public class S7WStringTests
+ {
+ [TestMethod]
+ public void ReadEmptyStringWithZeroLength()
+ {
+ AssertFromByteArrayEquals("", 0, 0 , 0, 0);
+ }
+
+ [TestMethod]
+ public void ReadEmptyStringWithOneCharLength()
+ {
+ AssertFromByteArrayEquals("", 0, 1, 0, 0, 0, 0);
+ }
+
+ [TestMethod]
+ public void ReadEmptyStringWithOneCharGarbage()
+ {
+
+ AssertFromByteArrayEquals("", 0, 1, 0, 0, 0x00, 0x41);
+ }
+
+ [TestMethod]
+ public void ReadMalformedStringTooShort()
+ {
+ Assert.ThrowsException(() => AssertFromByteArrayEquals("", 0, 1));
+ }
+
+ [TestMethod]
+ public void ReadMalformedStringSizeLargerThanCapacity()
+ {
+ Assert.ThrowsException(() => S7WString.FromByteArray(new byte[] { 0, 3, 0, 5, 0, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41}));
+ }
+
+ [TestMethod]
+ public void ReadMalformedStringCapacityTooLarge()
+ {
+ Assert.ThrowsException(() => AssertToByteArrayAndBackEquals("", 20000, 0));
+ }
+
+ [TestMethod]
+ public void ReadA()
+ {
+ AssertFromByteArrayEquals("A", 0, 1, 0, 1, 0x00, 0x41);
+ }
+
+ [TestMethod]
+ public void ReadAbc()
+ {
+ AssertFromByteArrayEquals("Abc", 0, 3, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63);
+ }
+
+ [TestMethod]
+ public void WriteNullWithReservedLengthZero()
+ {
+ Assert.ThrowsException(() => AssertToByteArrayAndBackEquals(null, 0, 0, 0, 0, 0));
+ }
+
+ [TestMethod]
+ public void WriteEmptyStringWithReservedLengthZero()
+ {
+ AssertToByteArrayAndBackEquals("", 0, 0, 0, 0, 0);
+ }
+
+ [TestMethod]
+ public void WriteAWithReservedLengthZero()
+ {
+ AssertToByteArrayAndBackEquals("", 0, 0, 0, 0, 0);
+ }
+
+ [TestMethod]
+ public void WriteNullWithReservedLengthOne()
+ {
+ Assert.ThrowsException(() => AssertToByteArrayAndBackEquals(null, 1, 0, 1 , 0, 0));
+ }
+
+ [TestMethod]
+ public void WriteEmptyStringWithReservedLengthOne()
+ {
+ AssertToByteArrayAndBackEquals("", 1, 0, 1, 0, 0, 0, 0);
+ }
+
+ [TestMethod]
+ public void WriteAWithReservedLengthOne()
+ {
+ AssertToByteArrayAndBackEquals("A", 1, 0, 1, 0, 1, 0x00, 0x41);
+ }
+
+ [TestMethod]
+ public void WriteAWithReservedLengthTwo()
+ {
+ AssertToByteArrayAndBackEquals("A", 2, 0, 2, 0, 1, 0x00, 0x41, 0, 0);
+ }
+
+ [TestMethod]
+ public void WriteAbcWithStringLargerThanReservedLength()
+ {
+ Assert.ThrowsException(() => S7WString.ToByteArray("Abc", 2));
+ }
+
+ [TestMethod]
+ public void WriteAbcWithReservedLengthThree()
+ {
+ AssertToByteArrayAndBackEquals("Abc", 3, 0, 3, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63);
+ }
+
+ [TestMethod]
+ public void WriteAbcWithReservedLengthFour()
+ {
+ AssertToByteArrayAndBackEquals("Abc", 4, 0, 4, 0, 3, 0x00, 0x41, 0x00, 0x62, 0x00, 0x63, 0 , 0);
+ }
+
+ private static void AssertFromByteArrayEquals(string expected, params byte[] bytes)
+ {
+ var convertedString = S7WString.FromByteArray(bytes);
+ Assert.AreEqual(expected, convertedString);
+ }
+
+
+ private static void AssertToByteArrayAndBackEquals(string value, int reservedLength, params byte[] expected)
+ {
+ var convertedData = S7WString.ToByteArray(value, reservedLength);
+ CollectionAssert.AreEqual(expected, convertedData);
+ var convertedBack = S7WString.FromByteArray(convertedData);
+ Assert.AreEqual(value, convertedBack);
+ }
+ }
+}
diff --git a/S7.Net/Enums.cs b/S7.Net/Enums.cs
index c523ad7..436d94b 100644
--- a/S7.Net/Enums.cs
+++ b/S7.Net/Enums.cs
@@ -178,6 +178,11 @@
///
S7String,
+ ///
+ /// S7 WString variable type (variable)
+ ///
+ S7WString,
+
///
/// Timer variable type
///
diff --git a/S7.Net/PLCAddress.cs b/S7.Net/PLCAddress.cs
index fd30b94..9aea1b0 100644
--- a/S7.Net/PLCAddress.cs
+++ b/S7.Net/PLCAddress.cs
@@ -183,7 +183,7 @@
case "Z":
case "C":
// Counter
- dataType = DataType.Timer;
+ dataType = DataType.Counter;
dbNumber = 0;
address = int.Parse(input.Substring(1));
varType = VarType.Counter;
@@ -204,4 +204,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/S7.Net/PLCHelpers.cs b/S7.Net/PLCHelpers.cs
index 1668e08..4c4f8ac 100644
--- a/S7.Net/PLCHelpers.cs
+++ b/S7.Net/PLCHelpers.cs
@@ -125,6 +125,8 @@ namespace S7.Net
return Types.String.FromByteArray(bytes);
case VarType.S7String:
return S7String.FromByteArray(bytes);
+ case VarType.S7WString:
+ return S7WString.FromByteArray(bytes);
case VarType.Timer:
if (varCount == 1)
diff --git a/S7.Net/PlcAsynchronous.cs b/S7.Net/PlcAsynchronous.cs
index b6b49c6..42b61a7 100644
--- a/S7.Net/PlcAsynchronous.cs
+++ b/S7.Net/PlcAsynchronous.cs
@@ -35,6 +35,7 @@ namespace S7.Net
catch(Exception)
{
stream.Dispose();
+ throw;
}
}
diff --git a/S7.Net/Protocol/Serialization.cs b/S7.Net/Protocol/Serialization.cs
index ceecaa6..3d114b6 100644
--- a/S7.Net/Protocol/Serialization.cs
+++ b/S7.Net/Protocol/Serialization.cs
@@ -17,10 +17,14 @@ namespace S7.Net.Protocol
{
throw new Exception($"DataItem.Value is null, cannot serialize. StartAddr={dataItem.StartByteAdr} VarType={dataItem.VarType}");
}
+
if (dataItem.Value is string s)
- return dataItem.VarType == VarType.S7String
- ? S7String.ToByteArray(s, dataItem.Count)
- : Types.String.ToByteArray(s, dataItem.Count);
+ return dataItem.VarType switch
+ {
+ VarType.S7String => S7String.ToByteArray(s, dataItem.Count),
+ VarType.S7WString => S7WString.ToByteArray(s, dataItem.Count),
+ _ => Types.String.ToByteArray(s, dataItem.Count)
+ };
return SerializeValue(dataItem.Value);
}
@@ -46,7 +50,7 @@ namespace S7.Net.Protocol
case "Double":
return Types.LReal.ToByteArray((double)value);
case "DateTime":
- return Types.DateTime.ToByteArray((System.DateTime) value);
+ return Types.DateTime.ToByteArray((System.DateTime)value);
case "Byte[]":
return (byte[])value;
case "Int16[]":
@@ -64,10 +68,10 @@ namespace S7.Net.Protocol
case "String":
// Hack: This is backwards compatible with the old code, but functionally it's broken
// if the consumer does not pay attention to string length.
- var stringVal = (string) value;
+ var stringVal = (string)value;
return Types.String.ToByteArray(stringVal, stringVal.Length);
case "DateTime[]":
- return Types.DateTime.ToByteArray((System.DateTime[]) value);
+ return Types.DateTime.ToByteArray((System.DateTime[])value);
case "DateTimeLong[]":
return Types.DateTimeLong.ToByteArray((System.DateTime[])value);
default:
diff --git a/S7.Net/S7.Net.csproj b/S7.Net/S7.Net.csproj
index 868f03b..85ef368 100644
--- a/S7.Net/S7.Net.csproj
+++ b/S7.Net/S7.Net.csproj
@@ -20,6 +20,7 @@
portable
true
snupkg
+ true
diff --git a/S7.Net/Types/S7String.cs b/S7.Net/Types/S7String.cs
index 6210e53..5bc383e 100644
--- a/S7.Net/Types/S7String.cs
+++ b/S7.Net/Types/S7String.cs
@@ -45,7 +45,7 @@ namespace S7.Net.Types
/// Converts a to S7 string with 2-byte header.
///
/// The string to convert to byte array.
- /// The length (in bytes) allocated in PLC for string excluding header.
+ /// 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)
{
@@ -54,7 +54,7 @@ namespace S7.Net.Types
throw new ArgumentNullException(nameof(value));
}
- if (reservedLength > byte.MaxValue) throw new ArgumentException($"The maximum string length supported is {byte.MaxValue}.");
+ if (reservedLength > 254) throw new ArgumentException($"The maximum string length supported is 254.");
var bytes = Encoding.ASCII.GetBytes(value);
if (bytes.Length > reservedLength) throw new ArgumentException($"The provided string length ({bytes.Length} is larger than the specified reserved length ({reservedLength}).");
diff --git a/S7.Net/Types/S7StringAttribute.cs b/S7.Net/Types/S7StringAttribute.cs
new file mode 100644
index 0000000..4d6e107
--- /dev/null
+++ b/S7.Net/Types/S7StringAttribute.cs
@@ -0,0 +1,67 @@
+using System;
+
+namespace S7.Net.Types
+{
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
+ public sealed class S7StringAttribute : Attribute
+ {
+ private readonly S7StringType type;
+ private readonly int reservedLength;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The string type.
+ /// Reserved length of the string in characters.
+ /// Please use a valid value for the string type
+ public S7StringAttribute(S7StringType type, int reservedLength)
+ {
+ if (!Enum.IsDefined(typeof(S7StringType), type))
+ throw new ArgumentException("Please use a valid value for the string type");
+
+ this.type = type;
+ this.reservedLength = reservedLength;
+ }
+
+ ///
+ /// Gets the type of the string.
+ ///
+ ///
+ /// The string type.
+ ///
+ public S7StringType Type => type;
+
+ ///
+ /// Gets the reserved length of the string in characters.
+ ///
+ ///
+ /// The reserved length of the string in characters.
+ ///
+ public int ReservedLength => reservedLength;
+
+ ///
+ /// Gets the reserved length in bytes.
+ ///
+ ///
+ /// The reserved length in bytes.
+ ///
+ public int ReservedLengthInBytes => type == S7StringType.S7String ? reservedLength + 2 : (reservedLength * 2) + 4;
+ }
+
+
+ ///
+ /// String type.
+ ///
+ public enum S7StringType
+ {
+ ///
+ /// ASCII string.
+ ///
+ S7String = VarType.S7String,
+
+ ///
+ /// Unicode string.
+ ///
+ S7WString = VarType.S7WString
+ }
+}
diff --git a/S7.Net/Types/S7WString.cs b/S7.Net/Types/S7WString.cs
new file mode 100644
index 0000000..8d8aabf
--- /dev/null
+++ b/S7.Net/Types/S7WString.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Text;
+
+namespace S7.Net.Types
+{
+ ///
+ /// Contains the methods to convert from S7 wstrings to C# strings
+ /// An S7 WString has a preceding 4 byte header containing its capacity and length
+ ///
+ public static class S7WString
+ {
+ ///
+ /// Converts S7 bytes to a string
+ ///
+ ///
+ ///
+ public static string FromByteArray(byte[] bytes)
+ {
+ if (bytes.Length < 4)
+ {
+ throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / too short");
+ }
+
+ int size = (bytes[0] << 8) | bytes[1];
+ int length = (bytes[2] << 8) | bytes[3];
+
+ if (length > size)
+ {
+ throw new PlcException(ErrorCode.ReadData, "Malformed S7 WString / length larger than capacity");
+ }
+
+ try
+ {
+ return Encoding.BigEndianUnicode.GetString(bytes, 4, length * 2);
+ }
+ catch (Exception e)
+ {
+ throw new PlcException(ErrorCode.ReadData,
+ $"Failed to parse {VarType.S7WString} from data. Following fields were read: size: '{size}', actual length: '{length}', total number of bytes (including header): '{bytes.Length}'.",
+ e);
+ }
+
+ }
+
+ ///
+ /// Converts a to S7 wstring with 4-byte header.
+ ///
+ /// 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)
+ {
+ if (value is null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if (reservedLength > 16382) throw new ArgumentException("The maximum string length supported is 16382.");
+
+ var buffer = new byte[4 + reservedLength * 2];
+ buffer[0] = (byte)((reservedLength >> 8) & 0xFF);
+ buffer[1] = (byte)(reservedLength & 0xFF);
+ buffer[2] = (byte)((value.Length >> 8) & 0xFF);
+ buffer[3] = (byte)(value.Length & 0xFF);
+
+ var stringLength = Encoding.BigEndianUnicode.GetBytes(value, 0, value.Length, buffer, 4) / 2;
+ if (stringLength > reservedLength) throw new ArgumentException($"The provided string length ({stringLength} is larger than the specified reserved length ({reservedLength}).");
+
+ return buffer;
+ }
+ }
+}
diff --git a/S7.Net/Types/Struct.cs b/S7.Net/Types/Struct.cs
index 1e126a5..1e95508 100644
--- a/S7.Net/Types/Struct.cs
+++ b/S7.Net/Types/Struct.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Reflection;
namespace S7.Net.Types
@@ -18,11 +19,11 @@ namespace S7.Net.Types
double numBytes = 0.0;
var infos = structType
- #if NETSTANDARD1_3
+#if NETSTANDARD1_3
.GetTypeInfo().DeclaredFields;
- #else
+#else
.GetFields();
- #endif
+#endif
foreach (var info in infos)
{
@@ -61,6 +62,16 @@ namespace S7.Net.Types
numBytes++;
numBytes += 8;
break;
+ case "String":
+ S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault();
+ if (attribute == default(S7StringAttribute))
+ throw new ArgumentException("Please add S7StringAttribute to the string field");
+
+ numBytes = Math.Ceiling(numBytes);
+ if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
+ numBytes++;
+ numBytes += attribute.ReservedLengthInBytes;
+ break;
default:
numBytes += GetStructSize(info.FieldType);
break;
@@ -91,11 +102,11 @@ namespace S7.Net.Types
var infos = structValue.GetType()
- #if NETSTANDARD1_3
+#if NETSTANDARD1_3
.GetTypeInfo().DeclaredFields;
- #else
+#else
.GetFields();
- #endif
+#endif
foreach (var info in infos)
{
@@ -120,7 +131,7 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]);
info.SetValue(structValue, source.ConvertToShort());
numBytes += 2;
@@ -129,7 +140,7 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
info.SetValue(structValue, Word.FromBytes(bytes[(int)numBytes + 1],
bytes[(int)numBytes]));
numBytes += 2;
@@ -138,7 +149,7 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3],
bytes[(int)numBytes + 2],
bytes[(int)numBytes + 1],
@@ -150,7 +161,7 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
info.SetValue(structValue, DWord.FromBytes(bytes[(int)numBytes],
bytes[(int)numBytes + 1],
bytes[(int)numBytes + 2],
@@ -161,7 +172,7 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
info.SetValue(structValue, Real.FromByteArray(new byte[] { bytes[(int)numBytes],
bytes[(int)numBytes + 1],
bytes[(int)numBytes + 2],
@@ -172,12 +183,38 @@ namespace S7.Net.Types
numBytes = Math.Ceiling(numBytes);
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
numBytes++;
- // hier auswerten
+ // get the value
var data = new byte[8];
Array.Copy(bytes, (int)numBytes, data, 0, 8);
info.SetValue(structValue, LReal.FromByteArray(data));
numBytes += 8;
break;
+ case "String":
+ S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault();
+ if (attribute == default(S7StringAttribute))
+ throw new ArgumentException("Please add S7StringAttribute to the string field");
+
+ numBytes = Math.Ceiling(numBytes);
+ if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
+ numBytes++;
+
+ // get the value
+ var sData = new byte[attribute.ReservedLengthInBytes];
+ Array.Copy(bytes, (int)numBytes, sData, 0, sData.Length);
+ switch (attribute.Type)
+ {
+ case S7StringType.S7String:
+ info.SetValue(structValue, S7String.FromByteArray(sData));
+ break;
+ case S7StringType.S7WString:
+ info.SetValue(structValue, S7WString.FromByteArray(sData));
+ break;
+ default:
+ throw new ArgumentException("Please use a valid string type for the S7StringAttribute");
+ }
+
+ numBytes += sData.Length;
+ break;
default:
var buffer = new byte[GetStructSize(info.FieldType)];
if (buffer.Length == 0)
@@ -209,11 +246,11 @@ namespace S7.Net.Types
double numBytes = 0.0;
var infos = type
- #if NETSTANDARD1_3
+#if NETSTANDARD1_3
.GetTypeInfo().DeclaredFields;
- #else
+#else
.GetFields();
- #endif
+#endif
foreach (var info in infos)
{
@@ -254,6 +291,18 @@ namespace S7.Net.Types
case "Double":
bytes2 = LReal.ToByteArray((double)info.GetValue(structValue));
break;
+ case "String":
+ S7StringAttribute? attribute = info.GetCustomAttributes().SingleOrDefault();
+ if (attribute == default(S7StringAttribute))
+ throw new ArgumentException("Please add S7StringAttribute to the string field");
+
+ bytes2 = attribute.Type switch
+ {
+ 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;
}
if (bytes2 != null)
{
@@ -269,7 +318,5 @@ namespace S7.Net.Types
}
return bytes;
}
-
-
}
}