diff --git a/S7.Net.UnitTest/Helpers/TestClass.cs b/S7.Net.UnitTest/Helpers/TestClass.cs index 0c221e2..c810adc 100644 --- a/S7.Net.UnitTest/Helpers/TestClass.cs +++ b/S7.Net.UnitTest/Helpers/TestClass.cs @@ -35,12 +35,12 @@ namespace S7.Net.UnitTest.Helpers /// /// DB1.DBD4 /// - public double RealVariableDouble { get; set; } + public double LRealVariable { get; set; } /// /// DB1.DBD8 /// - public float RealVariableFloat { get; set; } + public float RealVariable { get; set; } /// /// DB1.DBD12 diff --git a/S7.Net.UnitTest/Helpers/TestStruct.cs b/S7.Net.UnitTest/Helpers/TestStruct.cs index 2b70374..c40c6f4 100644 --- a/S7.Net.UnitTest/Helpers/TestStruct.cs +++ b/S7.Net.UnitTest/Helpers/TestStruct.cs @@ -35,12 +35,12 @@ namespace S7.Net.UnitTest.Helpers /// /// DB1.DBD4 /// - public double RealVariableDouble; + public double LRealVariable; /// /// DB1.DBD8 /// - public float RealVariableFloat; + public float RealVariable; /// /// DB1.DBD12 diff --git a/S7.Net.UnitTest/S7NetTestsAsync.cs b/S7.Net.UnitTest/S7NetTestsAsync.cs index e03a490..47ff56c 100644 --- a/S7.Net.UnitTest/S7NetTestsAsync.cs +++ b/S7.Net.UnitTest/S7NetTestsAsync.cs @@ -101,20 +101,13 @@ namespace S7.Net.UnitTest /// /// Read/Write a single REAL with a single request. - /// Test that writing a double and reading it gives the correct value. + /// Test that writing a float and reading it gives the correct value. /// [TestMethod] public async Task Test_Async_WriteAndReadRealVariables() { Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor."); - // Reading and writing a double is quite complicated, because it needs to be converted to DWord before the write, - // then reconvert to double after the read. - double val = 35.68729; - await plc.WriteAsync("DB1.DBD40", val.ConvertToUInt()); - double result = ((uint)await plc.ReadAsync("DB1.DBD40")).ConvertToDouble(); - Assert.AreEqual(val, Math.Round(result, 5)); // float lose precision, so i need to round it - // Reading and writing a float is quite complicated, because it needs to be converted to DWord before the write, // then reconvert to float after the read. Float values can contain only 7 digits, so no precision is lost. float val2 = 1234567; @@ -162,8 +155,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; @@ -175,8 +168,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(tc.RealVariableDouble, Math.Round(tc2.RealVariableDouble, 3)); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); } @@ -219,8 +212,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; plc.WriteStruct(tc, DB2); @@ -230,8 +223,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(tc.RealVariableDouble, Math.Round(tc2.RealVariableDouble, 3)); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); } @@ -584,8 +577,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; @@ -599,8 +592,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(tc.RealVariableDouble, tc2.RealVariableDouble, 0.1); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable, 0.1); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); Assert.AreEqual(TestClassWithPrivateSetters.PRIVATE_SETTER_VALUE, tc2.PrivateSetterProperty); @@ -632,8 +625,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; @@ -649,8 +642,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2.BitVariable10, tc2Generic.BitVariable10); Assert.AreEqual(tc2.DIntVariable, tc2Generic.DIntVariable); Assert.AreEqual(tc2.IntVariable, tc2Generic.IntVariable); - Assert.AreEqual(Math.Round(tc2.RealVariableDouble, 3), Math.Round(tc2Generic.RealVariableDouble, 3)); - Assert.AreEqual(tc2.RealVariableFloat, tc2Generic.RealVariableFloat); + Assert.AreEqual(Math.Round(tc2.LRealVariable, 3), Math.Round(tc2Generic.LRealVariable, 3)); + Assert.AreEqual(tc2.RealVariable, tc2Generic.RealVariable); Assert.AreEqual(tc2.DWordVariable, tc2Generic.DWordVariable); } @@ -675,8 +668,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; @@ -689,8 +682,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2Generic.BitVariable00, tc2GenericWithClassFactory.BitVariable00); Assert.AreEqual(tc2Generic.BitVariable10, tc2GenericWithClassFactory.BitVariable10); Assert.AreEqual(tc2Generic.DIntVariable, tc2GenericWithClassFactory.DIntVariable); - Assert.AreEqual(Math.Round(tc2Generic.RealVariableDouble, 3), Math.Round(tc2GenericWithClassFactory.RealVariableDouble, 3)); - Assert.AreEqual(tc2Generic.RealVariableFloat, tc2GenericWithClassFactory.RealVariableFloat); + Assert.AreEqual(Math.Round(tc2Generic.LRealVariable, 3), Math.Round(tc2GenericWithClassFactory.LRealVariable, 3)); + Assert.AreEqual(tc2Generic.RealVariable, tc2GenericWithClassFactory.RealVariable); Assert.AreEqual(tc2Generic.DWordVariable, tc2GenericWithClassFactory.DWordVariable); } @@ -747,8 +740,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; @@ -763,8 +756,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(ts2.BitVariable10, ts2Generic.BitVariable10); Assert.AreEqual(ts2.DIntVariable, ts2Generic.DIntVariable); Assert.AreEqual(ts2.IntVariable, ts2Generic.IntVariable); - Assert.AreEqual(Math.Round(ts2.RealVariableDouble, 3), Math.Round(ts2Generic.RealVariableDouble, 3)); - Assert.AreEqual(ts2.RealVariableFloat, ts2Generic.RealVariableFloat); + Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable); + Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable); Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable); } @@ -792,8 +785,8 @@ namespace S7.Net.UnitTest BitVariable10 = true, DIntVariable = -100000, IntVariable = -15000, - RealVariableDouble = -154.789, - RealVariableFloat = -154.789f, + LRealVariable = -154.789, + RealVariable = -154.789f, DWordVariable = 850 }; plc.WriteClass(tc, DB2); @@ -883,16 +876,16 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.CustomTypes[1].Bools[1], tc2.CustomTypes[1].Bools[1]); } - [TestMethod] - public async Task Test_Async_ReadWriteDouble() - { - double test_value = 55.66; - await plc.WriteAsync("DB1.DBD0", test_value); - var helper = await plc.ReadAsync("DB1.DBD0"); - double test_value2 = Conversion.ConvertToDouble((uint)helper); + //[TestMethod] + //public async Task Test_Async_ReadWriteDouble() + //{ + // double test_value = 55.66; + // await plc.WriteAsync("DB1.DBD0", test_value); + // var helper = await plc.ReadAsync("DB1.DBD0"); + // double test_value2 = Conversion.ConvertToDouble((uint)helper); - Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals - } + // Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals + //} [TestMethod] public async Task Test_Async_ReadWriteSingle() diff --git a/S7.Net.UnitTest/S7NetTestsSync.cs b/S7.Net.UnitTest/S7NetTestsSync.cs index e2e563e..fd63448 100644 --- a/S7.Net.UnitTest/S7NetTestsSync.cs +++ b/S7.Net.UnitTest/S7NetTestsSync.cs @@ -146,20 +146,13 @@ namespace S7.Net.UnitTest /// /// Read/Write a single REAL with a single request. - /// Test that writing a double and reading it gives the correct value. + /// Test that writing a float and reading it gives the correct value. /// [TestMethod] public void T03_WriteAndReadRealVariables() { Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor."); - // Reading and writing a double is quite complicated, because it needs to be converted to DWord before the write, - // then reconvert to double after the read. - double val = 35.68729; - plc.Write("DB1.DBD40", val.ConvertToUInt()); - double result = ((uint)plc.Read("DB1.DBD40")).ConvertToDouble(); - Assert.AreEqual(val, Math.Round(result, 5)); // float lose precision, so i need to round it - // Reading and writing a float is quite complicated, because it needs to be converted to DWord before the write, // then reconvert to float after the read. Float values can contain only 7 digits, so no precision is lost. float val2 = 1234567; @@ -186,8 +179,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteClass(tc, DB2); TestClass tc2 = new TestClass(); @@ -197,8 +190,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(Math.Round(tc.RealVariableDouble, 3), Math.Round(tc2.RealVariableDouble, 3)); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); } @@ -215,8 +208,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteStruct(tc, DB2); // Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct @@ -225,8 +218,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(tc.RealVariableDouble, Math.Round(tc2.RealVariableDouble, 3)); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); } @@ -575,8 +568,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteClass(tc, DB2); @@ -588,8 +581,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10); Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable); Assert.AreEqual(tc.IntVariable, tc2.IntVariable); - Assert.AreEqual(Math.Round(tc.RealVariableDouble, 3), Math.Round(tc2.RealVariableDouble, 3)); - Assert.AreEqual(tc.RealVariableFloat, tc2.RealVariableFloat); + Assert.AreEqual(tc.LRealVariable, tc2.LRealVariable); + Assert.AreEqual(tc.RealVariable, tc2.RealVariable); Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable); Assert.AreEqual(TestClassWithPrivateSetters.PRIVATE_SETTER_VALUE, tc2.PrivateSetterProperty); @@ -620,8 +613,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteClass(tc, DB2); @@ -635,8 +628,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2.BitVariable10, tc2Generic.BitVariable10); Assert.AreEqual(tc2.DIntVariable, tc2Generic.DIntVariable); Assert.AreEqual(tc2.IntVariable, tc2Generic.IntVariable); - Assert.AreEqual(Math.Round(tc2.RealVariableDouble, 3), Math.Round(tc2Generic.RealVariableDouble, 3)); - Assert.AreEqual(tc2.RealVariableFloat, tc2Generic.RealVariableFloat); + Assert.AreEqual(Math.Round(tc2.LRealVariable, 3), Math.Round(tc2Generic.LRealVariable, 3)); + Assert.AreEqual(tc2.RealVariable, tc2Generic.RealVariable); Assert.AreEqual(tc2.DWordVariable, tc2Generic.DWordVariable); } @@ -663,8 +656,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteClass(tc, DB2); @@ -677,8 +670,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(tc2Generic.BitVariable10, tc2GenericWithClassFactory.BitVariable10); Assert.AreEqual(tc2Generic.DIntVariable, tc2GenericWithClassFactory.DIntVariable); Assert.AreEqual(tc2Generic.IntVariable, tc2GenericWithClassFactory.IntVariable); - Assert.AreEqual(Math.Round(tc2Generic.RealVariableDouble, 3), Math.Round(tc2GenericWithClassFactory.RealVariableDouble, 3)); - Assert.AreEqual(tc2Generic.RealVariableFloat, tc2GenericWithClassFactory.RealVariableFloat); + Assert.AreEqual(Math.Round(tc2Generic.LRealVariable, 3), Math.Round(tc2GenericWithClassFactory.LRealVariable, 3)); + Assert.AreEqual(tc2Generic.RealVariable, tc2GenericWithClassFactory.RealVariable); Assert.AreEqual(tc2Generic.DWordVariable, tc2GenericWithClassFactory.DWordVariable); } @@ -786,8 +779,8 @@ namespace S7.Net.UnitTest ts.BitVariable10 = true; ts.DIntVariable = -100000; ts.IntVariable = -15000; - ts.RealVariableDouble = -154.789; - ts.RealVariableFloat = -154.789f; + ts.LRealVariable = -154.789; + ts.RealVariable = -154.789f; ts.DWordVariable = 850; plc.WriteStruct(ts, DB2); @@ -800,8 +793,8 @@ namespace S7.Net.UnitTest Assert.AreEqual(ts2.BitVariable10, ts2Generic.BitVariable10); Assert.AreEqual(ts2.DIntVariable, ts2Generic.DIntVariable); Assert.AreEqual(ts2.IntVariable, ts2Generic.IntVariable); - Assert.AreEqual(Math.Round(ts2.RealVariableDouble, 3), Math.Round(ts2Generic.RealVariableDouble, 3)); - Assert.AreEqual(ts2.RealVariableFloat, ts2Generic.RealVariableFloat); + Assert.AreEqual(ts2.LRealVariable, ts2Generic.LRealVariable); + Assert.AreEqual(ts2.RealVariable, ts2Generic.RealVariable); Assert.AreEqual(ts2.DWordVariable, ts2Generic.DWordVariable); } @@ -831,8 +824,8 @@ namespace S7.Net.UnitTest tc.BitVariable10 = true; tc.DIntVariable = -100000; tc.IntVariable = -15000; - tc.RealVariableDouble = -154.789; - tc.RealVariableFloat = -154.789f; + tc.LRealVariable = -154.789; + tc.RealVariable = -154.789f; tc.DWordVariable = 850; plc.WriteClass(tc, DB2); @@ -948,11 +941,10 @@ namespace S7.Net.UnitTest public void T26_ReadWriteDouble() { double test_value = 55.66; - plc.Write("DB1.DBD0", test_value); - var helper = plc.Read("DB1.DBD0"); - double test_value2 = Conversion.ConvertToDouble((uint)helper); + plc.Write(DataType.DataBlock, 1, 0, test_value); + var result = (double)plc.Read(DataType.DataBlock, 1, 0, VarType.LReal, 1); - Assert.AreEqual(test_value, test_value2, 0.01, "Compare Write/Read"); //Need delta here because S7 only has 32 bit reals + Assert.AreEqual(test_value, result, "Compare Write/Read"); } [TestMethod] diff --git a/S7.Net/Conversion.cs b/S7.Net/Conversion.cs index 09cdd4d..44f9e25 100644 --- a/S7.Net/Conversion.cs +++ b/S7.Net/Conversion.cs @@ -199,19 +199,6 @@ namespace S7.Net return output; } - /// - /// Converts from double to DWord (DBD) - /// - /// - /// - [Obsolete("Double support is obsolete. Use ConvertToUInt(float) instead.")] - public static UInt32 ConvertToUInt(this double input) - { - uint output; - output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Double.ToByteArray(input)); - return output; - } - /// /// Converts from float to DWord (DBD) /// @@ -220,20 +207,7 @@ namespace S7.Net public static UInt32 ConvertToUInt(this float input) { uint output; - output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Single.ToByteArray(input)); - return output; - } - - /// - /// Converts from DWord (DBD) to double - /// - /// - /// - [Obsolete("Double support is obsolete. Use ConvertToFloat(uint) instead.")] - public static double ConvertToDouble(this uint input) - { - double output; - output = S7.Net.Types.Double.FromByteArray(S7.Net.Types.DWord.ToByteArray(input)); + output = S7.Net.Types.DWord.FromByteArray(S7.Net.Types.Real.ToByteArray(input)); return output; } @@ -245,7 +219,7 @@ namespace S7.Net public static float ConvertToFloat(this uint input) { float output; - output = S7.Net.Types.Single.FromByteArray(S7.Net.Types.DWord.ToByteArray(input)); + output = S7.Net.Types.Real.FromByteArray(S7.Net.Types.DWord.ToByteArray(input)); return output; } } diff --git a/S7.Net/Enums.cs b/S7.Net/Enums.cs index 6082d28..fdb96ff 100644 --- a/S7.Net/Enums.cs +++ b/S7.Net/Enums.cs @@ -163,6 +163,11 @@ /// Real, + /// + /// LReal variable type (64 bits, 8 bytes) + /// + LReal, + /// /// String variable type (variable) /// diff --git a/S7.Net/PLCHelpers.cs b/S7.Net/PLCHelpers.cs index 9325f8a..ae1ff29 100644 --- a/S7.Net/PLCHelpers.cs +++ b/S7.Net/PLCHelpers.cs @@ -111,9 +111,14 @@ namespace S7.Net return DInt.ToArray(bytes); case VarType.Real: if (varCount == 1) - return Types.Single.FromByteArray(bytes); + return Types.Real.FromByteArray(bytes); else - return Types.Single.ToArray(bytes); + return Types.Real.ToArray(bytes); + case VarType.LReal: + if (varCount == 1) + return Types.LReal.FromByteArray(bytes); + else + return Types.LReal.ToArray(bytes); case VarType.String: return Types.String.FromByteArray(bytes); @@ -192,6 +197,7 @@ namespace S7.Net case VarType.DInt: case VarType.Real: return varCount * 4; + case VarType.LReal: case VarType.DateTime: return varCount * 8; case VarType.DateTimeLong: diff --git a/S7.Net/Protocol/Serialization.cs b/S7.Net/Protocol/Serialization.cs index 66142c2..de7fb84 100644 --- a/S7.Net/Protocol/Serialization.cs +++ b/S7.Net/Protocol/Serialization.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using S7.Net.Types; namespace S7.Net.Protocol @@ -37,10 +38,10 @@ namespace S7.Net.Protocol return Types.DInt.ToByteArray((Int32)value); case "UInt32": return Types.DWord.ToByteArray((UInt32)value); - case "Double": - return Types.Double.ToByteArray((double)value); case "Single": - return Types.Single.ToByteArray((float)value); + return Types.Real.ToByteArray((float)value); + case "Double": + return Types.LReal.ToByteArray((double)value); case "DateTime": return Types.DateTime.ToByteArray((System.DateTime) value); case "Byte[]": @@ -53,10 +54,10 @@ namespace S7.Net.Protocol return Types.DInt.ToByteArray((Int32[])value); case "UInt32[]": return Types.DWord.ToByteArray((UInt32[])value); - case "Double[]": - return Types.Double.ToByteArray((double[])value); case "Single[]": - return Types.Single.ToByteArray((float[])value); + return Types.Real.ToByteArray((float[])value); + case "Double[]": + return Types.LReal.ToByteArray((double[])value); 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. diff --git a/S7.Net/Types/Class.cs b/S7.Net/Types/Class.cs index ab76f8d..ecb59ac 100644 --- a/S7.Net/Types/Class.cs +++ b/S7.Net/Types/Class.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; @@ -51,12 +52,17 @@ namespace S7.Net.Types numBytes += 4; break; case "Single": - case "Double": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; numBytes += 4; break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 8; + break; default: var propertyClass = Activator.CreateInstance(type); numBytes = GetClassSize(propertyClass, numBytes, true); @@ -168,12 +174,12 @@ namespace S7.Net.Types bytes[(int)numBytes + 3]); numBytes += 4; break; - case "Double": + case "Single": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; // hier auswerten - value = Double.FromByteArray( + value = Real.FromByteArray( new byte[] { bytes[(int)numBytes], bytes[(int)numBytes + 1], @@ -181,18 +187,15 @@ namespace S7.Net.Types bytes[(int)numBytes + 3] }); numBytes += 4; break; - case "Single": + case "Double": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; + var buffer = new byte[8]; + Array.Copy(bytes, (int)numBytes, buffer, 0, 8); // hier auswerten - value = Single.FromByteArray( - new byte[] { - bytes[(int)numBytes], - bytes[(int)numBytes + 1], - bytes[(int)numBytes + 2], - bytes[(int)numBytes + 3] }); - numBytes += 4; + value = LReal.FromByteArray(buffer); + numBytes += 8; break; default: var propClass = Activator.CreateInstance(propertyType); @@ -277,11 +280,11 @@ namespace S7.Net.Types case "UInt32": bytes2 = DWord.ToByteArray((UInt32)propertyValue); break; - case "Double": - bytes2 = Double.ToByteArray((double)propertyValue); - break; case "Single": - bytes2 = Single.ToByteArray((float)propertyValue); + bytes2 = Real.ToByteArray((float)propertyValue); + break; + case "Double": + bytes2 = LReal.ToByteArray((double)propertyValue); break; default: numBytes = ToBytes(propertyValue, bytes, numBytes); diff --git a/S7.Net/Types/Double.cs b/S7.Net/Types/Double.cs index 857784f..c9daf24 100644 --- a/S7.Net/Types/Double.cs +++ b/S7.Net/Types/Double.cs @@ -5,27 +5,13 @@ namespace S7.Net.Types /// /// Contains the conversion methods to convert Real from S7 plc to C# double. /// + [Obsolete("Class Double is obsolete. Use Real instead for 32bit floating point, or LReal for 64bit floating point.")] public static class Double { /// /// Converts a S7 Real (4 bytes) to double /// - public static double FromByteArray(byte[] bytes) - { - if (bytes.Length != 4) - { - throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); - } - - // sps uses bigending so we have to reverse if platform needs - if (BitConverter.IsLittleEndian) - { - // create deep copy of the array and reverse - bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; - } - - return BitConverter.ToSingle(bytes, 0); - } + public static double FromByteArray(byte[] bytes) => Real.FromByteArray(bytes); /// /// Converts a S7 DInt to double @@ -51,16 +37,7 @@ namespace S7.Net.Types /// /// Converts a double to S7 Real (4 bytes) /// - public static byte[] ToByteArray(double value) - { - byte[] bytes = BitConverter.GetBytes((float)(value)); - - // sps uses bigending so we have to check if platform is same - if (!BitConverter.IsLittleEndian) return bytes; - - // create deep copy of the array and reverse - return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; - } + public static byte[] ToByteArray(double value) => Real.ToByteArray((float)value); /// /// Converts an array of double to an array of bytes diff --git a/S7.Net/Types/LReal.cs b/S7.Net/Types/LReal.cs new file mode 100644 index 0000000..c541645 --- /dev/null +++ b/S7.Net/Types/LReal.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +namespace S7.Net.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# double. + /// + public static class LReal + { + /// + /// Converts a S7 LReal (8 bytes) to double + /// + public static double FromByteArray(byte[] bytes) + { + if (bytes.Length != 8) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 8 bytes."); + } + var buffer = bytes; + + // sps uses bigending so we have to reverse if platform needs + if (BitConverter.IsLittleEndian) + { + Array.Reverse(buffer); + } + + return BitConverter.ToDouble(buffer, 0); + } + + /// + /// Converts a double to S7 LReal (8 bytes) + /// + public static byte[] ToByteArray(double value) + { + var bytes = BitConverter.GetBytes(value); + + // sps uses bigending so we have to check if platform is same + if (BitConverter.IsLittleEndian) + { + Array.Reverse(bytes); + } + return bytes; + } + + /// + /// Converts an array of double to an array of bytes + /// + public static byte[] ToByteArray(double[] value) => TypeHelper.ToByteArray(value, ToByteArray); + + /// + /// Converts an array of S7 LReal to an array of double + /// + public static double[] ToArray(byte[] bytes) => TypeHelper.ToArray(bytes, FromByteArray); + + } +} diff --git a/S7.Net/Types/Real.cs b/S7.Net/Types/Real.cs new file mode 100644 index 0000000..1d28202 --- /dev/null +++ b/S7.Net/Types/Real.cs @@ -0,0 +1,75 @@ +using System; +using System.IO; + +namespace S7.Net.Types +{ + /// + /// Contains the conversion methods to convert Real from S7 plc to C# double. + /// + public static class Real + { + /// + /// Converts a S7 Real (4 bytes) to float + /// + public static float FromByteArray(byte[] bytes) + { + if (bytes.Length != 4) + { + throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); + } + + // sps uses bigending so we have to reverse if platform needs + if (BitConverter.IsLittleEndian) + { + // create deep copy of the array and reverse + bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; + } + + return BitConverter.ToSingle(bytes, 0); + } + + /// + /// Converts a float to S7 Real (4 bytes) + /// + public static byte[] ToByteArray(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + + // sps uses bigending so we have to check if platform is same + if (!BitConverter.IsLittleEndian) return bytes; + + // create deep copy of the array and reverse + return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; + } + + /// + /// Converts an array of float to an array of bytes + /// + public static byte[] ToByteArray(float[] value) + { + var buffer = new byte[4 * value.Length]; + var stream = new MemoryStream(buffer); + foreach (var val in value) + { + stream.Write(ToByteArray(val), 0, 4); + } + + return buffer; + } + + /// + /// Converts an array of S7 Real to an array of float + /// + public static float[] ToArray(byte[] bytes) + { + var values = new float[bytes.Length / 4]; + + int counter = 0; + for (int cnt = 0; cnt < bytes.Length / 4; cnt++) + values[cnt] = FromByteArray(new byte[] { bytes[counter++], bytes[counter++], bytes[counter++], bytes[counter++] }); + + return values; + } + + } +} diff --git a/S7.Net/Types/Single.cs b/S7.Net/Types/Single.cs index 3121efa..4f27553 100644 --- a/S7.Net/Types/Single.cs +++ b/S7.Net/Types/Single.cs @@ -5,27 +5,13 @@ namespace S7.Net.Types /// /// Contains the conversion methods to convert Real from S7 plc to C# float. /// + [Obsolete("Class Single is obsolete. Use Real instead.")] public static class Single { /// /// Converts a S7 Real (4 bytes) to float /// - public static float FromByteArray(byte[] bytes) - { - if (bytes.Length != 4) - { - throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); - } - - // sps uses bigending so we have to reverse if platform needs - if (BitConverter.IsLittleEndian) - { - // create deep copy of the array and reverse - bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; - } - - return BitConverter.ToSingle(bytes, 0); - } + public static float FromByteArray(byte[] bytes) => Real.FromByteArray(bytes); /// /// Converts a S7 DInt to float @@ -51,16 +37,7 @@ namespace S7.Net.Types /// /// Converts a double to S7 Real (4 bytes) /// - public static byte[] ToByteArray(float value) - { - byte[] bytes = BitConverter.GetBytes((float)(value)); - - // sps uses bigending so we have to check if platform is same - if (!BitConverter.IsLittleEndian) return bytes; - - // create deep copy of the array and reverse - return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }; - } + public static byte[] ToByteArray(float value) => Real.ToByteArray(value); /// /// Converts an array of float to an array of bytes diff --git a/S7.Net/Types/Struct.cs b/S7.Net/Types/Struct.cs index 733800a..1e126a5 100644 --- a/S7.Net/Types/Struct.cs +++ b/S7.Net/Types/Struct.cs @@ -50,12 +50,17 @@ namespace S7.Net.Types numBytes += 4; break; case "Single": - case "Double": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; numBytes += 4; break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + numBytes += 8; + break; default: numBytes += GetStructSize(info.FieldType); break; @@ -152,28 +157,27 @@ namespace S7.Net.Types bytes[(int)numBytes + 3])); numBytes += 4; break; - case "Double": - numBytes = Math.Ceiling(numBytes); - if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) - numBytes++; - // hier auswerten - info.SetValue(structValue, Double.FromByteArray(new byte[] { bytes[(int)numBytes], - bytes[(int)numBytes + 1], - bytes[(int)numBytes + 2], - bytes[(int)numBytes + 3] })); - numBytes += 4; - break; case "Single": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; // hier auswerten - info.SetValue(structValue, Single.FromByteArray(new byte[] { bytes[(int)numBytes], + info.SetValue(structValue, Real.FromByteArray(new byte[] { bytes[(int)numBytes], bytes[(int)numBytes + 1], bytes[(int)numBytes + 2], bytes[(int)numBytes + 3] })); numBytes += 4; break; + case "Double": + numBytes = Math.Ceiling(numBytes); + if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) + numBytes++; + // hier auswerten + var data = new byte[8]; + Array.Copy(bytes, (int)numBytes, data, 0, 8); + info.SetValue(structValue, LReal.FromByteArray(data)); + numBytes += 8; + break; default: var buffer = new byte[GetStructSize(info.FieldType)]; if (buffer.Length == 0) @@ -244,11 +248,11 @@ namespace S7.Net.Types case "UInt32": bytes2 = DWord.ToByteArray((UInt32)info.GetValue(structValue)); break; - case "Double": - bytes2 = Double.ToByteArray((double)info.GetValue(structValue)); - break; case "Single": - bytes2 = Single.ToByteArray((float)info.GetValue(structValue)); + bytes2 = Real.ToByteArray((float)info.GetValue(structValue)); + break; + case "Double": + bytes2 = LReal.ToByteArray((double)info.GetValue(structValue)); break; } if (bytes2 != null) diff --git a/S7.Net/Types/TypeHelper.cs b/S7.Net/Types/TypeHelper.cs new file mode 100644 index 0000000..983299b --- /dev/null +++ b/S7.Net/Types/TypeHelper.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace S7.Net.Types +{ + internal static class TypeHelper + { + /// + /// Converts an array of T to an array of bytes + /// + public static byte[] ToByteArray(T[] value, Func converter) where T : struct + { + var buffer = new byte[Marshal.SizeOf(default(T)) * value.Length]; + var stream = new MemoryStream(buffer); + foreach (var val in value) + { + stream.Write(converter(val), 0, 4); + } + + return buffer; + } + + /// + /// Converts an array of T repesented as S7 binary data to an array of T + /// + public static T[] ToArray(byte[] bytes, Func converter) + { + var typeSize = Marshal.SizeOf(default(T)); + var entries = bytes.Length / typeSize; + var values = new T[entries]; + + for(int i = 0; i < entries; ++i) + { + var buffer = new byte[typeSize]; + Array.Copy(bytes, i * typeSize, buffer, 0, typeSize); + values[i] = converter(buffer); + } + + return values; + } + } +}