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

摘要:
=0);}//////将位的值设置为1,给定位的地址//publicstaticbyteSetBit{//)&0xFF表示通过0返回来清除高位字节的值;}///////将位值重新设置为0,给定位地址//public staticbyteClearBit{return;}3,ByteArray包装以下列表<Byte>classByteArray{list<Byte>list=newList<Byte˃();publicbyte〔〕Array{get{returnlist.ToArray();}}publicByteArray(){list=newList;}publicvoid Clear(){list=newList<bytes˃());}publicvoid Add{list.Add;}public void Add{list.AddRange;}publishvoid Add{list.AddRange,}4,ClassIEnumerable<PropertyInfo>GetAccessableProperties使用反射获取公共、非静态和非只读属性Info.numBytes是一个位置指针,指向ByteArray中下一个数据应存储的位置。对于位,对于Byte,+0.125位置与字节对齐,对于2+字节,+1位置与字节,并检测其是否对齐。如果不是,+1,偶数对齐,加上数量。对于非标准类型,迭代加法在这里不是很正确。不支持字符串,也不支持对齐。publicstaticclassClass{privatestaticEnumerable<PropertyInfo>GetAccessableProperties{returnclassType#ifNETFX_CORE.GetProperties()。其中(p=˃p.GetSetMethod()!

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

免责声明:文章转载自《详解S7源码(1)----Types》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SpringBoot(一)Android SurfaceView播放视频时横竖屏的调整下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Ubuntu16 编译源码安装MXNet 可变卷积Deformable-ConvNets GPU版

【引言】最近接手了公司的关于虫子识别的项目,使用MXNet框架开发,但是实际用的是Deformable-ConvNets. Deformable-ConvNets为微软研究研究院提出的可变卷积网络,可用于对图像中大小不一的物体识别,不是单单识别图中的猫和狗(它们都一般大小),而识别图像中不同种类的虫子(虫子本身小,而且难以区分),在这样的场景下很适合用可变...

若依管理系统源码分析-分页的实现以及post请求时的分页

场景 官方示例分页实现 前端调用实现 //一般在查询参数中定义分页变量 queryParams: { pageNum: 1, pageSize: 10}, //页面添加分页组件,传入分页变量 <pagination v-show="total>0":total="total":page.sync="queryParams.page...

java8学习之Stream源码分析

上一次已经将Collectors类中的各种系统收集器的源代码进行了完整的学习,而在之前咱们已经花了大量的篇幅对其Stream进行了详细的示例学习,如: 那接下来则通过源代码的角度来对Stream的运作原理进行深入的学习,比如:Stream里面提供了这么多方法都是如何实现的?串行流与并行流又是如何调用的?对于并行流它又是如何利用ForkJoin这样的一个框...

linux中patch命令 -p 选项

 patch命令和diff命令是linux打补丁的成对命令,diff 负责生产xxxxx.patch文件,patch命令负责将补丁打到要修改的源码上。但是patch命令的参数-p很容易使人迷惑,因为对-p 后面的数字理解不清晰,造成patch打不上,项目时间拖延,很是郁闷。后来仔细实践了一下,弄清楚了-p实际的含义。        举例说明更加容易看懂。比...

HashMap源码和并发异常问题分析

要点源码分析 HashMap允许键值对为null;HashTable则不允许,会报空指针异常; HashMap<String, String> map= new HashMap<>(2); map.put(null,null); map.put("1",null); Hash...

Springboot集成BeanValidation扩展二:加载jar中的资源文件

一、需求 今天在搭建Springboot框架的时候,又遇到一个需求:在多模块系统中,有些模块想自己管理BeanValidation的资源文件(默认是启动项目claspath下的 ValidationMessages.properties)。刚开始还天真地认为springboot会不会帮我们做了,结果并没有,于是就是撸源码了。 以下是我的实现和实现原理 二、...