private static System.DateTime FromByteArrayImpl(byte[] bytes) { if (bytes.Length != TypeLengthInBytes) { throw new ArgumentOutOfRangeException(nameof(bytes), bytes.Length, $"Parsing a DateTimeLong requires exactly 12 bytes of input data, input data is {bytes.Length} bytes long."); } var year = AssertRangeInclusive(Word.FromBytes(bytes[1], bytes[0]), 1970, 2262, "year"); var month = AssertRangeInclusive(bytes[2], 1, 12, "month"); var day = AssertRangeInclusive(bytes[3], 1, 31, "day of month"); var dayOfWeek = AssertRangeInclusive(bytes[4], 1, 7, "day of week"); var hour = AssertRangeInclusive(bytes[5], 0, 23, "hour"); var minute = AssertRangeInclusive(bytes[6], 0, 59, "minute"); var second = AssertRangeInclusive(bytes[7], 0, 59, "second"); ; var nanoseconds = AssertRangeInclusive <uint>(DWord.FromBytes(bytes[11], bytes[10], bytes[9], bytes[8]), 0, 999999999, "nanoseconds"); var time = new System.DateTime(year, month, day, hour, minute, second); return(time.AddTicks(nanoseconds / 100)); }
/// <summary> /// Converts a S7 DWord to double /// </summary> public static double FromDWord(UInt32 value) { byte[] b = DWord.ToByteArray(value); double d = FromByteArray(b); return(d); }
/// <summary> /// Converts a S7 DWord to float /// </summary> public static float FromDWord(UInt32 value) { byte[] b = DWord.ToByteArray(value); float d = FromByteArray(b); return(d); }
/// <summary> /// Converts a <see cref="T:System.DateTime" /> value to a byte array. /// </summary> /// <param name="dateTime">The DateTime value to convert.</param> /// <returns>A byte array containing the S7 DateTimeLong representation of <paramref name="dateTime" />.</returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown when the value of /// <paramref name="dateTime" /> is before <see cref="P:SpecMinimumDateTime" /> /// or after <see cref="P:SpecMaximumDateTime" />. /// </exception> public static byte[] ToByteArray(System.DateTime dateTime) { if (dateTime < SpecMinimumDateTime) { throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, $"Date time '{dateTime}' is before the minimum '{SpecMinimumDateTime}' supported in S7 DateTimeLong representation."); } if (dateTime > SpecMaximumDateTime) { throw new ArgumentOutOfRangeException(nameof(dateTime), dateTime, $"Date time '{dateTime}' is after the maximum '{SpecMaximumDateTime}' supported in S7 DateTimeLong representation."); } var stream = new MemoryStream(TypeLengthInBytes); // Convert Year stream.Write(Word.ToByteArray(Convert.ToUInt16(dateTime.Year)), 0, 2); // Convert Month stream.WriteByte(Convert.ToByte(dateTime.Month)); // Convert Day stream.WriteByte(Convert.ToByte(dateTime.Day)); // Convert WeekDay. NET DateTime starts with Sunday = 0, while S7DT has Sunday = 1. stream.WriteByte(Convert.ToByte(dateTime.DayOfWeek + 1)); // Convert Hour stream.WriteByte(Convert.ToByte(dateTime.Hour)); // Convert Minutes stream.WriteByte(Convert.ToByte(dateTime.Minute)); // Convert Seconds stream.WriteByte(Convert.ToByte(dateTime.Second)); // Convert Nanoseconds. Net DateTime has a representation of 1 Tick = 100ns. // Thus First take the ticks Mod 1 Second (1s = 10'000'000 ticks), and then Convert to nanoseconds. stream.Write(DWord.ToByteArray(Convert.ToUInt32(dateTime.Ticks % 10000000 * 100)), 0, 4); return(stream.ToArray()); }
/// <summary> /// Creates a struct of a specified type by an array of bytes. /// </summary> /// <param name="structType">The struct type</param> /// <param name="bytes">The array of bytes</param> /// <returns>The object depending on the struct type or null if fails(array-length != struct-length</returns> public static object FromBytes(Type structType, byte[] bytes) { if (bytes == null) { return(null); } if (bytes.Length != GetStructSize(structType)) { return(null); } // and decode it int bytePos = 0; int bitPos = 0; double numBytes = 0.0; object structValue = Activator.CreateInstance(structType); System.Reflection.FieldInfo[] infos = structValue.GetType().GetFields(); foreach (System.Reflection.FieldInfo info in infos) { switch (info.FieldType.Name) { 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) { info.SetValue(structValue, true); } else { info.SetValue(structValue, false); } numBytes += 0.125; break; case "Byte": numBytes = Math.Ceiling(numBytes); info.SetValue(structValue, (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]); info.SetValue(structValue, source.ConvertToShort()); numBytes += 2; break; case "UInt16": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) { numBytes++; } // hier auswerten info.SetValue(structValue, 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]); info.SetValue(structValue, sourceUInt.ConvertToInt()); numBytes += 4; break; case "UInt32": numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) { numBytes++; } // hier auswerten info.SetValue(structValue, 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 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; } } return(structValue); }
/// <summary> /// Creates a byte array depending on the struct type. /// </summary> /// <param name="structValue">The struct object</param> /// <returns>A byte array or null if fails.</returns> public static byte[] ToBytes(object structValue) { Type type = structValue.GetType(); int size = Struct.GetStructSize(type); byte[] bytes = new byte[size]; byte[] bytes2 = null; int bytePos = 0; int bitPos = 0; double numBytes = 0.0; System.Reflection.FieldInfo[] infos = type.GetFields(); foreach (System.Reflection.FieldInfo info in infos) { bytes2 = null; switch (info.FieldType.Name) { case "Boolean": // get the value bytePos = (int)Math.Floor(numBytes); bitPos = (int)((numBytes - (double)bytePos) / 0.125); if ((bool)info.GetValue(structValue)) { 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)info.GetValue(structValue); numBytes++; break; case "Int16": bytes2 = Int.ToByteArray((Int16)info.GetValue(structValue)); break; case "UInt16": bytes2 = Word.ToByteArray((UInt16)info.GetValue(structValue)); break; case "Int32": bytes2 = DInt.ToByteArray((Int32)info.GetValue(structValue)); break; case "UInt32": bytes2 = DWord.ToByteArray((UInt32)info.GetValue(structValue)); break; case "Double": bytes2 = Double.ToByteArray((double)info.GetValue(structValue)); 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; } } return(bytes); }
/// <summary> /// Creates a struct of a specified type by an array of bytes. /// </summary> /// <param name="sourceClass"></param> /// <param name="classType">The struct type</param> /// <param name="bytes">The array of bytes</param> /// <returns>The object depending on the struct type or null if fails(array-length != struct-length</returns> public static void FromBytes(object sourceClass, Type classType, byte[] bytes) { if (bytes == null) { return; } if (bytes.Length != GetClassSize(classType)) { return; } // and decode it int bytePos = 0; int bitPos = 0; double numBytes = 0.0; var properties = sourceClass.GetType().GetProperties(); foreach (var property in properties) { switch (property.PropertyType.Name) { 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; } } }
/// <summary> /// Creates a byte array depending on the struct type. /// </summary> /// <param name="sourceClass">The struct object</param> /// <returns>A byte array or null if fails.</returns> public static byte[] ToBytes(object sourceClass) { Type type = sourceClass.GetType(); int size = GetClassSize(type); byte[] bytes = new byte[size]; byte[] bytes2 = null; int bytePos = 0; int bitPos = 0; double numBytes = 0.0; var properties = sourceClass.GetType().GetProperties(); foreach (var property in properties) { bytes2 = null; switch (property.PropertyType.Name) { 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; } 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; } } return(bytes); }
/// <summary> /// Creates a struct of a specified type by an array of bytes. /// </summary> /// <param name="sourceClass"></param> /// <param name="classType">The struct type</param> /// <param name="bytes">The array of bytes</param> /// <returns>The object depending on the struct type or null if fails(array-length != struct-length</returns> public static void FromBytes(object sourceClass, Type classType, byte[] bytes) { if (bytes == null) return; if (bytes.Length != GetClassSize(classType)) return; // and decode it int bytePos = 0; int bitPos = 0; double numBytes = 0.0; var properties = sourceClass.GetType().GetProperties(); foreach (var property in properties) { switch (property.PropertyType.Name) { 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; } } }