mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 22:38:27 +08:00
Merge pull request #365 from MCPC10/StructStringSupport
Added support for string types in a struct
This commit is contained in:
@@ -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
|
||||
/// </summary>
|
||||
public bool BitVariable00;
|
||||
|
||||
public bool BitVariable01;
|
||||
public bool BitVariable02;
|
||||
public bool BitVariable03;
|
||||
@@ -19,6 +21,7 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// DB1.DBX1.0
|
||||
/// </summary>
|
||||
public bool BitVariable10;
|
||||
|
||||
public bool BitVariable11;
|
||||
public bool BitVariable12;
|
||||
public bool BitVariable13;
|
||||
@@ -51,5 +54,17 @@ namespace S7.Net.UnitTest.Helpers
|
||||
/// DB1.DBD16
|
||||
/// </summary>
|
||||
public ushort DWordVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX20.0
|
||||
/// </summary>
|
||||
[S7String(S7StringType.S7WString, 10)]
|
||||
public string WStringVariable;
|
||||
|
||||
/// <summary>
|
||||
/// DB1.DBX44.0
|
||||
/// </summary>
|
||||
[S7String(S7StringType.S7String, 10)]
|
||||
public string StringVariable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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))]
|
||||
|
||||
67
S7.Net/Types/S7StringAttribute.cs
Normal file
67
S7.Net/Types/S7StringAttribute.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="S7StringAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The string type.</param>
|
||||
/// <param name="reservedLength">Reserved length of the string in characters.</param>
|
||||
/// <exception cref="ArgumentException">Please use a valid value for the string type</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the string.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The string type.
|
||||
/// </value>
|
||||
public S7StringType Type => type;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved length of the string in characters.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The reserved length of the string in characters.
|
||||
/// </value>
|
||||
public int ReservedLength => reservedLength;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved length in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The reserved length in bytes.
|
||||
/// </value>
|
||||
public int ReservedLengthInBytes => type == S7StringType.S7String ? reservedLength + 2 : (reservedLength * 2) + 4;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// String type.
|
||||
/// </summary>
|
||||
public enum S7StringType
|
||||
{
|
||||
/// <summary>
|
||||
/// ASCII string.
|
||||
/// </summary>
|
||||
S7String = VarType.S7String,
|
||||
|
||||
/// <summary>
|
||||
/// Unicode string.
|
||||
/// </summary>
|
||||
S7WString = VarType.S7WString
|
||||
}
|
||||
}
|
||||
@@ -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<S7StringAttribute>().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<S7StringAttribute>().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<S7StringAttribute>().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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user