mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 22:38:27 +08:00
Classes with arrays can now be read/written from/to the plc
This commit is contained in:
24
S7.Net.UnitTest/Helpers/TestClassWithArrays.cs
Normal file
24
S7.Net.UnitTest/Helpers/TestClassWithArrays.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace S7.UnitTest.Helpers
|
||||
{
|
||||
public class TestClassWithArrays
|
||||
{
|
||||
public bool Bool { get; set; }
|
||||
public bool[] BoolValues { get; set; } = new bool[2];
|
||||
public bool[] Fillers { get; set; } = new bool[13];
|
||||
|
||||
public short[] Shorts { get; set; } = new short[2];
|
||||
public ushort[] UShorts { get; set; } = new ushort[2];
|
||||
public int[] Ints { get; set; } = new int[2];
|
||||
public double[] Doubles { get; set; } = new double[2];
|
||||
|
||||
public short Short { get; set; }
|
||||
public ushort UShort { get; set; }
|
||||
public int Int { get; set; }
|
||||
public double Double { get; set; }
|
||||
}
|
||||
}
|
||||
20
S7.Net.UnitTest/Helpers/TestClassWithCustomType.cs
Normal file
20
S7.Net.UnitTest/Helpers/TestClassWithCustomType.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace S7.UnitTest.Helpers
|
||||
{
|
||||
public class CustomType
|
||||
{
|
||||
public bool[] Bools { get; set; } = new bool[2];
|
||||
public bool[] Fillers { get; set; } = new bool[14];
|
||||
}
|
||||
|
||||
public class TestClassWithCustomType
|
||||
{
|
||||
public int Int { get; set; }
|
||||
public CustomType CustomType { get; set; }
|
||||
public CustomType[] CustomTypes { get; set; } = new CustomType[2];
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@
|
||||
<Compile Include="Helpers\ConsoleManager.cs" />
|
||||
<Compile Include="Helpers\NativeMethods.cs" />
|
||||
<Compile Include="Helpers\S7TestServer.cs" />
|
||||
<Compile Include="Helpers\TestClassWithArrays.cs" />
|
||||
<Compile Include="Helpers\TestClassWithCustomType.cs" />
|
||||
<Compile Include="Helpers\TestClassWithPrivateSetters.cs" />
|
||||
<Compile Include="Helpers\TestLongClass.cs" />
|
||||
<Compile Include="Snap7\snap7.net.cs" />
|
||||
|
||||
@@ -656,7 +656,7 @@ namespace S7.Net.UnitTest
|
||||
tc.DWordVariable = 850;
|
||||
plc.WriteClass(tc, DB2);
|
||||
|
||||
int expectedReadBytes = Types.Class.GetClassSize(tc.GetType());
|
||||
int expectedReadBytes = Types.Class.GetClassSize(tc);
|
||||
|
||||
TestClass tc2 = new TestClass();
|
||||
// Values that are read from a class are stored inside the class itself, that is passed by reference
|
||||
@@ -664,6 +664,77 @@ namespace S7.Net.UnitTest
|
||||
|
||||
Assert.AreEqual(expectedReadBytes, actualReadBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T22_ReadClassWithArray()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithArrays tc = new TestClassWithArrays();
|
||||
tc.Bool = true;
|
||||
tc.BoolValues[1] = true;
|
||||
tc.Int = int.MinValue;
|
||||
tc.Ints[0] = int.MinValue;
|
||||
tc.Ints[1] = int.MaxValue;
|
||||
tc.Short = short.MinValue;
|
||||
tc.Shorts[0] = short.MinValue;
|
||||
tc.Shorts[1] = short.MaxValue;
|
||||
tc.Double = float.MinValue;
|
||||
tc.Doubles[0] = float.MinValue + 1;
|
||||
tc.Doubles[1] = float.MaxValue;
|
||||
tc.UShort = ushort.MinValue + 1;
|
||||
tc.UShorts[0] = ushort.MinValue + 1;
|
||||
tc.UShorts[1] = ushort.MaxValue;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
TestClassWithArrays tc2 = plc.ReadClass<TestClassWithArrays>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Bool, tc2.Bool);
|
||||
Assert.AreEqual(tc.BoolValues[0], tc2.BoolValues[0]);
|
||||
Assert.AreEqual(tc.BoolValues[1], tc2.BoolValues[1]);
|
||||
|
||||
Assert.AreEqual(tc.Int, tc2.Int);
|
||||
Assert.AreEqual(tc.Ints[0], tc2.Ints[0]);
|
||||
Assert.AreEqual(tc.Ints[1], tc.Ints[1]);
|
||||
|
||||
Assert.AreEqual(tc.Short, tc2.Short);
|
||||
Assert.AreEqual(tc.Shorts[0], tc2.Shorts[0]);
|
||||
Assert.AreEqual(tc.Shorts[1], tc2.Shorts[1]);
|
||||
|
||||
Assert.AreEqual(tc.Double, tc2.Double);
|
||||
Assert.AreEqual(tc.Doubles[0], tc2.Doubles[0]);
|
||||
Assert.AreEqual(tc.Doubles[1], tc2.Doubles[1]);
|
||||
|
||||
Assert.AreEqual(tc.UShort, tc2.UShort);
|
||||
Assert.AreEqual(tc.UShorts[0], tc2.UShorts[0]);
|
||||
Assert.AreEqual(tc.UShorts[1], tc2.UShorts[1]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void T22_ReadClassWithArrayAndCustomType()
|
||||
{
|
||||
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
|
||||
|
||||
TestClassWithCustomType tc = new TestClassWithCustomType();
|
||||
tc.Int = int.MinValue;
|
||||
tc.CustomType = new CustomType();
|
||||
tc.CustomType.Bools[1] = true;
|
||||
tc.CustomTypes[0] = new CustomType();
|
||||
tc.CustomTypes[1] = new CustomType();
|
||||
tc.CustomTypes[0].Bools[0] = true;
|
||||
tc.CustomTypes[1].Bools[1] = true;
|
||||
|
||||
plc.WriteClass(tc, DB2);
|
||||
TestClassWithCustomType tc2 = plc.ReadClass<TestClassWithCustomType>(DB2);
|
||||
|
||||
Assert.AreEqual(tc.Int, tc2.Int);
|
||||
Assert.AreEqual(tc.CustomType.Bools[0], tc2.CustomType.Bools[0]);
|
||||
Assert.AreEqual(tc.CustomType.Bools[1], tc2.CustomType.Bools[1]);
|
||||
Assert.AreEqual(tc.CustomTypes[0].Bools[0], tc2.CustomTypes[0].Bools[0]);
|
||||
Assert.AreEqual(tc.CustomTypes[0].Bools[1], tc2.CustomTypes[0].Bools[1]);
|
||||
Assert.AreEqual(tc.CustomTypes[1].Bools[0], tc2.CustomTypes[1].Bools[0]);
|
||||
Assert.AreEqual(tc.CustomTypes[1].Bools[1], tc2.CustomTypes[1].Bools[1]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -535,12 +535,16 @@ namespace S7.Net
|
||||
/// <returns>The number of read bytes</returns>
|
||||
public int ReadClass(object sourceClass, int db, int startByteAdr = 0)
|
||||
{
|
||||
Type classType = sourceClass.GetType();
|
||||
int numBytes = Types.Class.GetClassSize(classType);
|
||||
int numBytes = Types.Class.GetClassSize(sourceClass);
|
||||
if(numBytes <= 0)
|
||||
{
|
||||
throw new Exception("The size of the class is less than 1 byte and therefore cannot be read");
|
||||
}
|
||||
|
||||
// now read the package
|
||||
var resultBytes = ReadBytes(DataType.DataBlock, db, startByteAdr, numBytes);
|
||||
// and decode it
|
||||
Types.Class.FromBytes(sourceClass, classType, resultBytes);
|
||||
Types.Class.FromBytes(sourceClass, resultBytes);
|
||||
|
||||
return resultBytes.Length;
|
||||
}
|
||||
|
||||
@@ -25,158 +25,268 @@ namespace S7.Net.Types
|
||||
|
||||
}
|
||||
|
||||
private static double GetIncreasedNumberOfBytes(double startingNumberOfBytes, Type type)
|
||||
{
|
||||
double numBytes = startingNumberOfBytes;
|
||||
|
||||
switch (type.Name)
|
||||
{
|
||||
case "Boolean":
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
case "UInt16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "Int32":
|
||||
case "UInt32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Float":
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
default:
|
||||
var propertyClass = Activator.CreateInstance(type);
|
||||
numBytes += GetClassSize(propertyClass);
|
||||
break;
|
||||
}
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the class in bytes.
|
||||
/// </summary>
|
||||
/// <param name="classType">the type of the class</param>
|
||||
/// <param name="instance">An instance of the class</param>
|
||||
/// <returns>the number of bytes</returns>
|
||||
public static int GetClassSize(Type classType)
|
||||
public static int GetClassSize(object instance)
|
||||
{
|
||||
double numBytes = 0.0;
|
||||
|
||||
var properties = GetAccessableProperties(classType);
|
||||
var properties = GetAccessableProperties(instance.GetType());
|
||||
foreach (var property in properties)
|
||||
{
|
||||
switch (property.PropertyType.Name)
|
||||
if (property.PropertyType.IsArray)
|
||||
{
|
||||
case "Boolean":
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
case "UInt16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "Int32":
|
||||
case "UInt32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Float":
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
numBytes += 4;
|
||||
break;
|
||||
default:
|
||||
numBytes += GetClassSize(property.PropertyType);
|
||||
break;
|
||||
Type elementType = property.PropertyType.GetElementType();
|
||||
Array array = (Array)property.GetValue(instance, null);
|
||||
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.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
numBytes = GetIncreasedNumberOfBytes(numBytes, elementType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numBytes = GetIncreasedNumberOfBytes(numBytes, property.PropertyType);
|
||||
}
|
||||
}
|
||||
return (int)numBytes;
|
||||
}
|
||||
|
||||
private static object GetPropertyValue(Type propertyType, byte[] bytes, ref double numBytes)
|
||||
{
|
||||
object value = null;
|
||||
|
||||
switch (propertyType.Name)
|
||||
{
|
||||
case "Boolean":
|
||||
// get the value
|
||||
int bytePos = (int)Math.Floor(numBytes);
|
||||
int bitPos = (int)((numBytes - (double)bytePos) / 0.125);
|
||||
if ((bytes[bytePos] & (int)Math.Pow(2, bitPos)) != 0)
|
||||
value = true;
|
||||
else
|
||||
value = false;
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
value = (byte)(bytes[(int)numBytes]);
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]);
|
||||
value = source.ConvertToShort();
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "UInt16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
value = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]);
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "Int32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 0]);
|
||||
value = sourceUInt.ConvertToInt();
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "UInt32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
value = DWord.FromBytes(
|
||||
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
|
||||
value = Double.FromByteArray(
|
||||
new byte[] {
|
||||
bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 3] });
|
||||
numBytes += 4;
|
||||
break;
|
||||
default:
|
||||
var propClass = Activator.CreateInstance(propertyType);
|
||||
var buffer = new byte[GetClassSize(propClass)];
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
Buffer.BlockCopy(bytes, (int)Math.Ceiling(numBytes), buffer, 0, buffer.Length);
|
||||
FromBytes(propClass, buffer);
|
||||
value = propClass;
|
||||
numBytes += buffer.Length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the object's values with the given array of bytes
|
||||
/// </summary>
|
||||
/// <param name="sourceClass">The object to fill in the given array of bytes</param>
|
||||
/// <param name="classType">The class type</param>
|
||||
/// <param name="bytes">The array of bytes</param>
|
||||
public static void FromBytes(object sourceClass, Type classType, byte[] bytes)
|
||||
public static void FromBytes(object sourceClass, byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return;
|
||||
|
||||
if (bytes.Length != GetClassSize(classType))
|
||||
if (bytes.Length != GetClassSize(sourceClass))
|
||||
return;
|
||||
|
||||
// and decode it
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
double numBytes = 0.0;
|
||||
|
||||
|
||||
var properties = GetAccessableProperties(classType);
|
||||
var properties = GetAccessableProperties(sourceClass.GetType());
|
||||
foreach (var property in properties)
|
||||
{
|
||||
switch (property.PropertyType.Name)
|
||||
if (property.PropertyType.IsArray)
|
||||
{
|
||||
case "Boolean":
|
||||
// get the value
|
||||
bytePos = (int)Math.Floor(numBytes);
|
||||
bitPos = (int)((numBytes - (double)bytePos) / 0.125);
|
||||
if ((bytes[bytePos] & (int)Math.Pow(2, bitPos)) != 0)
|
||||
property.SetValue(sourceClass, true, null);
|
||||
else
|
||||
property.SetValue(sourceClass, false, null);
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
property.SetValue(sourceClass, (byte)(bytes[(int)numBytes]), null);
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
ushort source = Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]);
|
||||
property.SetValue(sourceClass, source.ConvertToShort(), null);
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "UInt16":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
property.SetValue(sourceClass, Word.FromBytes(bytes[(int)numBytes + 1], bytes[(int)numBytes]), null);
|
||||
numBytes += 2;
|
||||
break;
|
||||
case "Int32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
uint sourceUInt = DWord.FromBytes(bytes[(int)numBytes + 3],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 0]);
|
||||
property.SetValue(sourceClass, sourceUInt.ConvertToInt(), null);
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "UInt32":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
property.SetValue(sourceClass, DWord.FromBytes(bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 3]), null);
|
||||
numBytes += 4;
|
||||
break;
|
||||
case "Double":
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
// hier auswerten
|
||||
property.SetValue(sourceClass, Double.FromByteArray(new byte[] { bytes[(int)numBytes],
|
||||
bytes[(int)numBytes + 1],
|
||||
bytes[(int)numBytes + 2],
|
||||
bytes[(int)numBytes + 3] }), null);
|
||||
numBytes += 4;
|
||||
break;
|
||||
default:
|
||||
var buffer = new byte[GetClassSize(property.PropertyType)];
|
||||
if (buffer.Length == 0)
|
||||
continue;
|
||||
Buffer.BlockCopy(bytes, (int)Math.Ceiling(numBytes), buffer, 0, buffer.Length);
|
||||
var propClass = Activator.CreateInstance(property.PropertyType);
|
||||
FromBytes(propClass, property.PropertyType, buffer);
|
||||
property.SetValue(sourceClass, propClass, null);
|
||||
numBytes += buffer.Length;
|
||||
break;
|
||||
Array array = (Array)property.GetValue(sourceClass, null);
|
||||
Type elementType = property.PropertyType.GetElementType();
|
||||
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
|
||||
{
|
||||
array.SetValue(
|
||||
GetPropertyValue(elementType, bytes, ref numBytes),
|
||||
i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
property.SetValue(
|
||||
sourceClass,
|
||||
GetPropertyValue(property.PropertyType, bytes, ref numBytes),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToBytes(Type propertyType, object propertyValue, byte[] bytes, ref double numBytes)
|
||||
{
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
byte[] bytes2 = null;
|
||||
|
||||
switch (propertyType.Name)
|
||||
{
|
||||
case "Boolean":
|
||||
// get the value
|
||||
bytePos = (int)Math.Floor(numBytes);
|
||||
bitPos = (int)((numBytes - (double)bytePos) / 0.125);
|
||||
if ((bool)propertyValue)
|
||||
bytes[bytePos] |= (byte)Math.Pow(2, bitPos); // is true
|
||||
else
|
||||
bytes[bytePos] &= (byte)(~(byte)Math.Pow(2, bitPos)); // is false
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = (int)Math.Ceiling(numBytes);
|
||||
bytePos = (int)numBytes;
|
||||
bytes[bytePos] = (byte)propertyValue;
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
bytes2 = Int.ToByteArray((Int16)propertyValue);
|
||||
break;
|
||||
case "UInt16":
|
||||
bytes2 = Word.ToByteArray((UInt16)propertyValue);
|
||||
break;
|
||||
case "Int32":
|
||||
bytes2 = DInt.ToByteArray((Int32)propertyValue);
|
||||
break;
|
||||
case "UInt32":
|
||||
bytes2 = DWord.ToByteArray((UInt32)propertyValue);
|
||||
break;
|
||||
case "Double":
|
||||
bytes2 = Double.ToByteArray((double)propertyValue);
|
||||
break;
|
||||
default:
|
||||
bytes2 = ToBytes(propertyValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes2 != null)
|
||||
{
|
||||
// add them
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
bytePos = (int)numBytes;
|
||||
for (int bCnt = 0; bCnt < bytes2.Length; bCnt++)
|
||||
bytes[bytePos + bCnt] = bytes2[bCnt];
|
||||
numBytes += bytes2.Length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,67 +297,28 @@ namespace S7.Net.Types
|
||||
/// <returns>A byte array or null if fails.</returns>
|
||||
public static byte[] ToBytes(object sourceClass)
|
||||
{
|
||||
Type type = sourceClass.GetType();
|
||||
|
||||
int size = GetClassSize(type);
|
||||
int size = GetClassSize(sourceClass);
|
||||
byte[] bytes = new byte[size];
|
||||
byte[] bytes2 = null;
|
||||
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
double numBytes = 0.0;
|
||||
|
||||
var properties = GetAccessableProperties(sourceClass.GetType());
|
||||
foreach (var property in properties)
|
||||
{
|
||||
bytes2 = null;
|
||||
switch (property.PropertyType.Name)
|
||||
if (property.PropertyType.IsArray)
|
||||
{
|
||||
case "Boolean":
|
||||
// get the value
|
||||
bytePos = (int)Math.Floor(numBytes);
|
||||
bitPos = (int)((numBytes - (double)bytePos) / 0.125);
|
||||
if ((bool)property.GetValue(sourceClass, null))
|
||||
bytes[bytePos] |= (byte)Math.Pow(2, bitPos); // is true
|
||||
else
|
||||
bytes[bytePos] &= (byte)(~(byte)Math.Pow(2, bitPos)); // is false
|
||||
numBytes += 0.125;
|
||||
break;
|
||||
case "Byte":
|
||||
numBytes = (int)Math.Ceiling(numBytes);
|
||||
bytePos = (int)numBytes;
|
||||
bytes[bytePos] = (byte)property.GetValue(sourceClass, null);
|
||||
numBytes++;
|
||||
break;
|
||||
case "Int16":
|
||||
bytes2 = Int.ToByteArray((Int16)property.GetValue(sourceClass, null));
|
||||
break;
|
||||
case "UInt16":
|
||||
bytes2 = Word.ToByteArray((UInt16)property.GetValue(sourceClass, null));
|
||||
break;
|
||||
case "Int32":
|
||||
bytes2 = DInt.ToByteArray((Int32)property.GetValue(sourceClass, null));
|
||||
break;
|
||||
case "UInt32":
|
||||
bytes2 = DWord.ToByteArray((UInt32)property.GetValue(sourceClass, null));
|
||||
break;
|
||||
case "Double":
|
||||
bytes2 = Double.ToByteArray((double)property.GetValue(sourceClass, null));
|
||||
break;
|
||||
Array array = (Array)property.GetValue(sourceClass, null);
|
||||
Type elementType = property.PropertyType.GetElementType();
|
||||
for (int i = 0; i < array.Length && numBytes < bytes.Length; i++)
|
||||
{
|
||||
ToBytes(elementType, array.GetValue(i), bytes, ref numBytes);
|
||||
}
|
||||
}
|
||||
if (bytes2 != null)
|
||||
else
|
||||
{
|
||||
// add them
|
||||
numBytes = Math.Ceiling(numBytes);
|
||||
if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0)
|
||||
numBytes++;
|
||||
bytePos = (int)numBytes;
|
||||
for (int bCnt = 0; bCnt < bytes2.Length; bCnt++)
|
||||
bytes[bytePos + bCnt] = bytes2[bCnt];
|
||||
numBytes += bytes2.Length;
|
||||
ToBytes(property.PropertyType, property.GetValue(sourceClass, null), bytes, ref numBytes);
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user