• 详解S7源码(1)----Types


    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(略)

  • 相关阅读:
    用位运算实现十进制转换为二进制
    【Zhejiang University PATest】02-3. 求前缀表达式的值
    【Zhejiang University PATest】02-1. Reversing Linked List
    【Tsinghua OJ】隧道(Tunel)问题
    冒泡排序及其优化
    有序向量的查找算法
    【Tsinghua OJ】灯塔(LightHouse)问题
    有序向量的去重算法
    【Tsinghua OJ】祖玛(Zuma)问题
    倒水问题(《怎样解题》中的经典问题)
  • 原文地址:https://www.cnblogs.com/frogkiller/p/14678610.html
Copyright © 2020-2023  润新知