| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 | using DBHelper_SqlSugar;using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Reflection;using System.Runtime.InteropServices;using WCS.Entity;namespace WCS.Core{    public class DataBlock : EntityEx<WCS_DATABLOCK>    {        protected byte[] Data;        //{        //    get { return DataServer.Get(Entity); }        //}        private List<PlcItem> Values = new List<PlcItem>();        internal event Action<Db, byte[]> DataChanged;        /// <summary>        /// 是否失败,默认成功        /// </summary>        private bool failed = false;        public DataBlock(WCS_DATABLOCK entity) : base(entity)        {        }        private DateTime AliveTime = DateTime.Now;        public void DataRefresh()        {            var sw = new Stopwatch();            try            {                if (Entity.NOUPDATE && Data != null)                    return;                if (failed && (DateTime.Now - AliveTime).TotalMilliseconds < 3000)                {                    throw new Exception(Entity.NAME + "连接失败");                }                AliveTime = DateTime.Now;                byte[] data = null;                lock (Entity.PLC)                {                    sw.Start();                    data = Entity.PLC.Ex().Accessor.ReadBytes((ushort)Entity.NO, 0, (ushort)Entity.LENGTH);                    sw.Stop();                }                failed = false;                if (Data != null && data.SequenceEqual(Data)) return;                Data = data;                Db.Do(db =>                {                    DataChanged?.Invoke(db, Data);                });            }            catch (Exception)            {                sw.Stop();                failed = true;                throw;            }            finally            {                if (sw.ElapsedMilliseconds > 500)                {                    Console.ForegroundColor = ConsoleColor.Yellow;                    Console.WriteLine($"{Entity.PLC.NAME}{Entity.PLC.IP}访问耗时:{sw.ElapsedMilliseconds}");                    Console.ResetColor();                }            }        }        public PlcItem<T> Regist<T>(string objid, string name, int start, byte arrLen = 1, byte strLen = 0)        {            var t = typeof(T);            var pv = new PlcItem<T>(objid, name, this, start, arrLen, strLen);            Values.Add(pv);            return pv;        }        private ushort GetByteStart(int bitStart)        {            var res = bitStart / 8;            return (ushort)res;        }        private ushort GetBitIndex(int bitStart)        {            return (ushort)(bitStart % 8);        }        #region 读取        public T Read<T>(int bitStart, int strLength, int arrLength)        {            return (T)Read(typeof(T), ref bitStart, strLength, arrLength);        }        private object Read(Type type, ref int bitStart, int strLength, int arrLength)        {            if (failed)                throw new Exception(this.Entity.NAME + "连接失败");            if (type.IsArray)            {                var t = type.GetElementType();                if (t.IsArray)                {                    throw new Exception("只支持一维数组");                }                var arr = Array.CreateInstance(t, arrLength);                for (int i = 0; i < arr.Length; i++)                {                    var value = Read(t, ref bitStart, strLength, 0);                    arr.SetValue(value, i);                }                return arr;            }            else if (typeof(IList).IsAssignableFrom(type))            {                var t = type.GetGenericArguments().First();                var res = Activator.CreateInstance(type) as IList;                while (bitStart < Entity.LENGTH * 8)                {                    var value = Read(t, ref bitStart, strLength, 0);                    res.Add(value);                }                return res;            }            else if (type == typeof(bool))            {                return ReadBit(ref bitStart);            }            else if (type == typeof(string))            {                return ReadString(ref bitStart, strLength);            }            else if (type.IsEnum)            {                return ReadEnum(type, ref bitStart);            }            else if (type.IsPrimitive)            {                var revers = Entity.PLC.TYPE == PLCType.西门子;                return ReadPrimitive(type, ref bitStart, revers);                //var revers = Entity.PLC.TYPE == PLCType.西门子;                //return ReadPrimitive(type, ref bitStart, false);            }            else            {                if (type.IsValueType)                {                    //ushort size = (ushort)Marshal.SizeOf(type);                    //var s = bitStart;                    //var bytes = ReadBytes(ref s, size).Reverse().ToArray();                    //var o = ByteToStruct(type, bytes);                    var res = Activator.CreateInstance(type);                    foreach (var p in type.GetProperties())                    {                        var value = Read(p.PropertyType, ref bitStart, strLength, arrLength);                        p.SetValue(res, value);                    }                    return res;                }                else                    throw new Exception("类型不支持");            }        }        public static object ByteToStruct(Type type, byte[] dataBuffer)        {            int size = Marshal.SizeOf(type);            IntPtr allocIntPtr = Marshal.AllocHGlobal(size);            try            {                Marshal.Copy(dataBuffer, 0, allocIntPtr, size);                return Marshal.PtrToStructure(allocIntPtr, type);            }            finally            {                Marshal.FreeHGlobal(allocIntPtr);            }        }        private string ReadString(ref int bitStart, int strLen)        {            if (Entity.PLC.TYPE == PLCType.西门子)            {                var data = ReadBytes(ref bitStart, (ushort)(strLen + 2));                var len = data[1];                data = data.Skip(2).Take(len).ToArray();                var str = Configs.StringEncoding.GetString(data);                return str;            }            else            {                var data = ReadBytes(ref bitStart, (ushort)strLen);                var str = Configs.StringEncoding.GetString(data);                return str;            }        }        private object ReadEnum(Type enumType, ref int bitStart)        {            var type = enumType.GetEnumUnderlyingType();            var reverse = false;            if (enumType.GetCustomAttribute<FlagsAttribute>() == null)            {                reverse = Entity.PLC.TYPE == PLCType.西门子;            }            var value = ReadPrimitive(type, ref bitStart, reverse);            var res = Enum.Parse(enumType, value.ToString());            return res;        }        private object ReadPrimitive(Type type, ref int bitStart, bool reverse)        {            var size = (ushort)Marshal.SizeOf(type);            if (type == typeof(bool))                size = 1;            var data = ReadBytes(ref bitStart, size);            if (reverse)                data = data.Reverse().ToArray();            if (type == typeof(byte))            {                return data.First();            }            else if (type == typeof(bool))            {                return BitConverter.ToBoolean(data, 0);            }            else if (type == typeof(char))            {                return BitConverter.ToChar(data, 0);            }            else if (type == typeof(short))            {                return BitConverter.ToInt16(data, 0);            }            else if (type == typeof(ushort))            {                return BitConverter.ToUInt16(data, 0);            }            else if (type == typeof(int))            {                return BitConverter.ToInt32(data, 0);            }            else if (type == typeof(uint))            {                return BitConverter.ToUInt32(data, 0);            }            else if (type == typeof(long))            {                return BitConverter.ToInt64(data, 0);            }            else if (type == typeof(ulong))            {                return BitConverter.ToUInt64(data, 0);            }            else if (type == typeof(float))            {                return BitConverter.ToSingle(data, 0);            }            else if (type == typeof(double))            {                return BitConverter.ToDouble(data, 0);            }            else            {                throw new Exception("类型不支持");            }        }        private byte[] ReadBytes(ref int bitStart, ushort length)        {            var start = GetByteStart(bitStart);            var data = Data.Skip(start).Take(length).ToArray();            bitStart += length * 8;            return data;        }        private bool ReadBit(ref int bitStart)        {            var start = GetByteStart(bitStart);            var b = Data.Skip(start).First();            var bitIndex = GetBitIndex(bitStart);            bitStart++;            return b.GetBit(bitIndex);        }        #endregion 读取        #region 写入        public void Write<T>(int bitStart, T value, int strLength, int arrLength)        {            Write(typeof(T), ref bitStart, value, strLength, arrLength);        }        private void Write(Type type, ref int bitStart, object value, int strLength, int arrLength)        {            if (type.IsArray)            {                var t = type.GetElementType();                if (t.IsArray)                {                    throw new Exception("只支持一维数组");                }                var arr = value as Array;                if (arr.Length > arrLength)                    throw new Exception("数组长度超出");                foreach (var obj in arr)                {                    Write(obj.GetType(), ref bitStart, obj, strLength, arrLength);                }            }            else if (type == typeof(bool))            {                WriteBit(ref bitStart, (bool)value);            }            else if (type == typeof(string))            {                WriteString(ref bitStart, value.ToString(), strLength);            }            else if (type.IsEnum)            {                WriteEnum(ref bitStart, value);            }            else if (type.IsPrimitive)            {                var revers = Entity.PLC.TYPE == PLCType.西门子;                WritePrimitive(ref bitStart, value, revers);            }            else                throw new Exception("类型不支持");        }        private void WriteString(ref int bitStart, string value, int strLen)        {            var data = Configs.StringEncoding.GetBytes(value);            if (data.Length > strLen)                throw new Exception("字符串长度超出");            if (Entity.PLC.TYPE == PLCType.西门子)            {                var title = new byte[] { (byte)strLen, (byte)data.Length };                data = title.Concat(data).ToArray();            }            WriteBytes(ref bitStart, data);        }        private void WriteEnum(ref int bitStart, object value)        {            var etype = value.GetType();            var type = etype.GetEnumUnderlyingType();            var obj = Convert.ChangeType(value, type);            var reverse = false;            if (etype.GetCustomAttribute<FlagsAttribute>() == null)            {                reverse = Entity.PLC.TYPE == PLCType.西门子;            }            WritePrimitive(ref bitStart, obj, reverse);        }        private void WritePrimitive(ref int bitStart, object value, bool reverse)        {            var type = value.GetType();            byte[] data;            if (type == typeof(char))            {                data = BitConverter.GetBytes((char)value);            }            else if (type == typeof(byte))            {                data = new byte[] { (byte)value };            }            else if (type == typeof(short))            {                data = BitConverter.GetBytes((short)value);            }            else if (type == typeof(ushort))            {                data = BitConverter.GetBytes((ushort)value);            }            else if (type == typeof(int))            {                data = BitConverter.GetBytes((int)value);            }            else if (type == typeof(uint))            {                data = BitConverter.GetBytes((uint)value);            }            else if (type == typeof(long))            {                data = BitConverter.GetBytes((long)value);            }            else if (type == typeof(ulong))            {                data = BitConverter.GetBytes((ulong)value);            }            else            {                throw new Exception("类型不支持");            }            if (reverse)                data = data.Reverse().ToArray();            WriteBytes(ref bitStart, data);        }        private void WriteBytes(ref int bitStart, byte[] data)        {            lock (Entity.PLC)            {                var start = GetByteStart(bitStart);                //DataServer.WriteBytes(Entity, start, data);                Entity.PLC.Ex().Accessor.WriteBytes((ushort)Entity.NO, start, data);                data.CopyTo(Data, start);                bitStart += data.Length * 8;            }        }        private void WriteBit(ref int bitStart, bool flag)        {            lock (Entity.PLC)            {                var start = GetByteStart(bitStart);                var bitIndex = GetBitIndex(bitStart);                var b = Data.Skip(start).First();                b = b.SetBit(bitIndex, flag);                var data = new byte[] { b };                Entity.PLC.Ex().Accessor.WriteBytes((ushort)Entity.NO, (ushort)start, data);                data.CopyTo(Data, start);                bitStart += 1;            }        }        #endregion 写入    }}
 |