| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 | using System.Collections;using System.Reflection;using System.Runtime.InteropServices;namespace WCS.Core{    public class DataBlock : EntityEx<DBInfo>    {        public event Action<byte[]> DbChanged;        public static List<DataBlock> DBList = new List<DataBlock>();        private List<ProtocolProxyBase> ProxyList = new List<ProtocolProxyBase>();        public ushort Start { get; private set; }        public ushort Length { get; private set; }        public bool failed { get; private set; }        private byte[] Data = new byte[0];        private int id = 0;        public override string ToString()        {            return id.ToString();        }        public DataBlock(DBInfo ent) : base(ent)        {            DBList.Add(this);            id = DBList.Count;        }        private DateTime faildTime = DateTime.MinValue;        public void RefreshData()        {            var isPing = false;            try            {                if (failed && !Entity.PLCInfo.Ex().Ping)                {                    isPing = true;                    throw new Exception($"网络异常IP为{Entity.PLCInfo.IP}的设备PLC无法访问");                }                Start = (ushort)ProxyList.Min(v => v.Info.Position);                var last = ProxyList.OrderBy(v => v.Info.Position).Last();                Length = (ushort)(last.Info.Position + last.BytesCount);                var data = new byte[0];                lock (Entity.PLCInfo.Ex())                {                    data = Entity.PLCInfo.Ex().Accessor.ReadBytes(Entity.No, Start, (ushort)(Length - Start));                }                if (!Data.SequenceEqual(data))                {                    Data = data;                    DbChanged?.Invoke(Data);                }                failed = false;            }            catch (Exception ex)            {                failed = true;                if (isPing) throw new Exception($"{ex.Message}");                throw new Exception($"{ex.Message}:\r{ex.StackTrace}");            }        }        public PlcItem<T> Regist<T>(ProtocolProxyBase proxy, string objid, string name, int start, byte arrLen = 1, byte strLen = 0)        {            if (!ProxyList.Contains(proxy))                ProxyList.Add(proxy);            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)        {            try            {                bitStart -= Start * 8;                return (T)Read(typeof(T), ref bitStart, strLength, arrLength);            }            catch (Exception ex)            {                throw;            }        }        private object Read(Type type, ref int bitStart, int strLength, int arrLength)        {            if (failed)                throw new Exception(this.Entity.No + "连接失败");            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 < 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.PLCInfo.Type == PLCType.Siemens;                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.PLCInfo.Type == PLCType.Siemens)            {                var data = ReadBytes(ref bitStart, (ushort)(strLen));                //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.PLCInfo.Type == PLCType.Siemens;            }            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);            if (Data.Length < start + length)            {                string data1 = "";                foreach (var item in Data.ToList())                {                    data1 = data1 + $"[{item}]";                }                var msg = $"读取数据的位置超出数据总长度:";                msg = msg + $"Data--{Data.Length};";                msg = msg + $"bitStart--{bitStart};";                msg = msg + $"start--{start};";                msg = msg + $"length--{length};";                msg = msg + $"读取PLC传入参数{Entity.No},{Start},{(ushort)(Length - Start)};";                msg = msg + $"Data内容--{data1}";                throw new Exception(msg);            }            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.PLCInfo.Type == PLCType.Siemens;                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.PLCInfo.Type == PLCType.Siemens)            //{            //    var a = Encoding.UTF8.GetString(data);            //    var title = new byte[] { (byte)strLen, (byte)data.Length };            //    data = title.Concat(data).ToArray();            //    var b = Encoding.UTF8.GetString(data);            //    var c = 0;            //}            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.PLCInfo.Type == PLCType.Siemens;            }            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.PLCInfo.Ex())            {                var start = GetByteStart(bitStart);                Entity.PLCInfo.Ex().Accessor.WriteBytes(Entity.No, start, data);                data.CopyTo(Data, start - Start);                bitStart += data.Length * 8;            }        }        private void WriteBit(ref int bitStart, bool flag)        {            lock (Entity.PLCInfo.Ex())            {                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.PLCInfo.Ex().Accessor.WriteBytes(Entity.No, (ushort)start, data);                data.CopyTo(Data, start - Start);                bitStart += 1;            }        }        #endregion 写入    }}
 |