1,Bit.cs
第一个布尔表达是,v前面加int强制原因是由于,&与操作符号是int,int类型
/// <summary> /// Contains the conversion methods to convert Bit from S7 plc to C#. /// </summary> public static class Bit { /// <summary> /// Converts a Bit to bool /// </summary> public static bool FromByte(byte v, byte bitAdr) { return (((int)v & (1 << bitAdr)) != 0); } /// <summary> /// Converts an array of bytes to a BitArray /// </summary> public static BitArray ToBitArray(byte[] bytes) { BitArray bitArr = new BitArray(bytes); return bitArr; } }
2,Boolean.cs
- 取字节或字中的某个位(((int)value & (1 << bit)) != 0);
- 置位字节或字节的某个位(byte)((value | (1 << bit)) & 0xFF); &0xff表示只取字节.
- 复位字节或字节的某个位return (byte)((value | (~(1 << bit))) & 0xFF); &0xff表示只取字节.这里是错误的,应改为
return (byte)((value & (~(1 << bit))) & 0xFF);
- 取反字或字节的某个位return (byte)((value ^ ((1 << bit))) & 0xFF);
/// <summary> /// Contains the methods to read, set and reset bits inside bytes /// </summary> public static class Boolean { /// <summary> /// Returns the value of a bit in a bit, given the address of the bit /// </summary> public static bool GetValue(byte value, int bit) { return (((int)value & (1 << bit)) != 0); } /// <summary> /// Sets the value of a bit to 1 (true), given the address of the bit /// </summary> public static byte SetBit(byte value, int bit) { // (1 << bit)) & 0xFF 表示将高字节的值清0 return (byte)((value | (1 << bit)) & 0xFF); } /// <summary> /// Resets the value of a bit to 0 (false), given the address of the bit /// </summary> public static byte ClearBit(byte value, int bit) { return (byte)((value | (~(1 << bit))) & 0xFF); } }
3,ByteArray
包装了下list<Byte>
class ByteArray { List<byte> list = new List<byte>(); public byte[] Array { get { return list.ToArray(); } } public ByteArray() { list = new List<byte>(); } public ByteArray(int size) { list = new List<byte>(size); } public void Clear() { list = new List<byte>(); } public void Add(byte item) { list.Add(item); } public void Add(byte[] items) { list.AddRange(items); } public void Add(ByteArray byteArray) { list.AddRange(byteArray.Array); } }
4,Class
- IEnumerable<PropertyInfo> GetAccessableProperties(Type classType)
用反射获取公共的,非静态的,非只读的属性Info.
- numBytes 是一个位置指针,指向下一个数据在ByteArray中应当存储的位置.
- 对于bit,+0.125个位置
- 对于Byte对齐到字节,并+1
- 对于2+的字节的,对齐到字节,并检测是否是偶对齐,如果不是,则+1,偶对齐,再加上数量.
- 对于非标准类型的,迭代添加,这里又是不怎么对.没有对String的支持以及没有偶对齐.
public static class Class { private static IEnumerable<PropertyInfo> GetAccessableProperties(Type classType) { return classType #if NETFX_CORE .GetProperties().Where(p => p.GetSetMethod() != null); #else .GetProperties( BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetSetMethod() != null); #endif } 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="instance">An instance of the class</param> /// <returns>the number of bytes</returns> public static int GetClassSize(object instance) { double numBytes = 0.0; var properties = GetAccessableProperties(instance.GetType()); foreach (var property in properties) { if (property.PropertyType.IsArray) { 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); } } // enlarge numBytes to next even number because S7-Structs in a DB always will be resized to an even byte count numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; 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="bytes">The array of bytes</param> public static void FromBytes(object sourceClass, byte[] bytes) { if (bytes == null) return; if (bytes.Length != GetClassSize(sourceClass)) return; // and decode it double numBytes = 0.0; var properties = GetAccessableProperties(sourceClass.GetType()); foreach (var property in properties) { if (property.PropertyType.IsArray) { 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(object propertyValue, byte[] bytes, ref double numBytes) { int bytePos = 0; int bitPos = 0; byte[] bytes2 = null; switch (propertyValue.GetType().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; } } /// <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) { int size = GetClassSize(sourceClass); byte[] bytes = new byte[size]; double numBytes = 0.0; var properties = GetAccessableProperties(sourceClass.GetType()); foreach (var property in properties) { if (property.PropertyType.IsArray) { Array array = (Array)property.GetValue(sourceClass, null); Type elementType = property.PropertyType.GetElementType(); for (int i = 0; i < array.Length && numBytes < bytes.Length; i++) { ToBytes(array.GetValue(i), bytes, ref numBytes); } } else { ToBytes(property.GetValue(sourceClass, null), bytes, ref numBytes); } } return bytes; } }
5,Counter 略
6,DataItem
表明了再哪个区域(DataType),读什么类型(Var Type),DB地址.如果非DB,则=0;起始BYte地址,如果读位,则标记位地址.
public class DataItem { /// <summary> /// Memory area to read /// </summary> public DataType DataType { get; set; } /// <summary> /// Type of data to be read (default is bytes) /// </summary> public VarType VarType { get; set; } /// <summary> /// Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45) /// </summary> public int DB { get; set; } /// <summary> /// Address of the first byte to read /// </summary> public int StartByteAdr { get; set; } /// <summary> /// Addess of bit to read from StartByteAdr /// </summary> public byte BitAdr { get; set; } /// <summary> /// Number of variables to read /// </summary> public int Count { get; set; } /// <summary> /// Contains the value of the memory area after the read has been executed /// </summary> public object Value { get; set; } /// <summary> /// Create an instance of DataItem /// </summary> public DataItem() { VarType = VarType.Byte; Count = 1; }
7,DInt
定义了单个DInt和Bytes以及数组DInt和BYtes之间的转换关系.
public static class DInt { /// <summary> /// Converts a S7 DInt (4 bytes) to int (Int32) /// </summary> public static Int32 FromByteArray(byte[] bytes) { if (bytes.Length != 4) { throw new ArgumentException("Wrong number of bytes. Bytes array must contain 4 bytes."); } return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]; } /// <summary> /// Converts a int (Int32) to S7 DInt (4 bytes) /// </summary> public static byte[] ToByteArray(Int32 value) { byte[] bytes = new byte[4]; bytes[0] = (byte)((value >> 24) & 0xFF); bytes[1] = (byte)((value >> 16) & 0xFF); bytes[2] = (byte)((value >> 8) & 0xFF); bytes[3] = (byte)((value) & 0xFF); return bytes; } /// <summary> /// Converts an array of int (Int32) to an array of bytes /// </summary> public static byte[] ToByteArray(Int32[] value) { ByteArray arr = new ByteArray(); foreach (Int32 val in value) arr.Add(ToByteArray(val)); return arr.Array; } /// <summary> /// Converts an array of S7 DInt to an array of int (Int32) /// </summary> public static Int32[] ToArray(byte[] bytes) { Int32[] values = new Int32[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; } }
8,Dboule
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); } /// <summary> /// Converts a S7 DInt to double /// </summary> public static double FromDWord(Int32 value) { byte[] b = DInt.ToByteArray(value); double d = FromByteArray(b); return d; } /// <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 double to S7 Real (4 bytes) /// </summary> 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] }; } /// <summary> /// Converts an array of double to an array of bytes /// </summary> public static byte[] ToByteArray(double[] value) { ByteArray arr = new ByteArray(); foreach (double val in value) arr.Add(ToByteArray(val)); return arr.Array; } /// <summary> /// Converts an array of S7 Real to an array of double /// </summary> public static double[] ToArray(byte[] bytes) { double[] values = new double[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; } }
9,DWord 略
10,Int 略
11,String
通过Encoding.ASCII.GetBytes进行转换.
public class String { /// <summary> /// Converts a string to S7 bytes /// </summary> public static byte[] ToByteArray(string value) { return System.Text.Encoding.ASCII.GetBytes(value); } /// <summary> /// Converts S7 bytes to a string /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static string FromByteArray(byte[] bytes) { return System.Text.Encoding.ASCII.GetString(bytes); } }
12,StringEx(不是很妥当)无,string转换为PLC类型的String,见PLCString.
13,Struct(略)类似Class
14,Timer(略)
15,Word(略)