123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- using System.Collections;
- using System.Reflection;
- using System.Runtime.InteropServices;
- namespace WCS.Core;
- public class DataBlock : EntityEx<DBInfo>
- {
- public static List<DataBlock> DBList = new();
- private byte[] Data = new byte[0];
- private DateTime faildTime = DateTime.MinValue;
- private readonly int id;
- private readonly List<ProtocolProxyBase> ProxyList = new();
- public DataBlock(DBInfo ent, World world) : base(ent)
- {
- World = world;
- DBList.Add(this);
- id = DBList.Count;
- }
- public ushort Start { get; private set; }
- public ushort Length { get; private set; }
- public World World { get; }
- public bool Failed { get; private set; } = true;
- public event Action<byte[]> DbChanged;
- public override string ToString()
- {
- return id.ToString();
- }
- public void RefreshData()
- {
- try
- {
- var plc = Entity.PLCInfo.Ex(World);
- if (Entity.PLCInfo.Type != PLCType.VitrualRedisPLC)
- if (Failed)
- if (!plc.Ping)
- {
- if (Entity.PLCInfo.IP == "1") throw new Exception($"{Entity.PLCInfo.IP}无法访问");
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"{Entity.PLCInfo.IP}无法访问");
- Console.ResetColor();
- throw new Exception($"{Entity.PLCInfo.IP}无法访问");
- }
- 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 (plc)
- {
-
- data = plc.Accessor.ReadBytes(Entity.No, Start, (ushort)(Length - Start));
-
- }
-
- if (!Data.SequenceEqual(data))
- {
- Data = data;
- DbChanged?.Invoke(Data);
- }
- Failed = false;
- }
- catch (Exception ex)
- {
- Failed = true;
- throw;
- }
- }
- 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)
- {
- bitStart -= Start * 8;
- 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(Entity.No + "连接失败");
- if (type.IsArray)
- {
- var t = type.GetElementType();
- if (t.IsArray) throw new Exception("只支持一维数组");
- var arr = Array.CreateInstance(t, arrLength);
- for (var i = 0; i < arr.Length; i++)
- {
- var value = Read(t, ref bitStart, strLength, 0);
- arr.SetValue(value, i);
- }
- return arr;
- }
- 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;
- }
- if (type == typeof(bool)) return ReadBit(ref bitStart);
- if (type == typeof(string)) return ReadString(ref bitStart, strLength);
- if (type.IsEnum) return ReadEnum(type, ref bitStart);
- 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);
- }
- 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;
- }
- throw new Exception("类型不支持");
- }
- public static object ByteToStruct(Type type, byte[] dataBuffer)
- {
- var size = Marshal.SizeOf(type);
- var 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();
- if (type == typeof(bool))
- return BitConverter.ToBoolean(data, 0);
- if (type == typeof(char))
- return BitConverter.ToChar(data, 0);
- if (type == typeof(short))
- return BitConverter.ToInt16(data, 0);
- if (type == typeof(ushort))
- return BitConverter.ToUInt16(data, 0);
- if (type == typeof(int))
- return BitConverter.ToInt32(data, 0);
- if (type == typeof(uint))
- return BitConverter.ToUInt32(data, 0);
- if (type == typeof(long))
- return BitConverter.ToInt64(data, 0);
- if (type == typeof(ulong))
- return BitConverter.ToUInt64(data, 0);
- if (type == typeof(float))
- return BitConverter.ToSingle(data, 0);
- if (type == typeof(double))
- return BitConverter.ToDouble(data, 0);
- throw new Exception("类型不支持");
- }
- private byte[] ReadBytes(ref int bitStart, ushort length)
- {
- var start = GetByteStart(bitStart);
- if (Data.Length < start + length)
- {
- var 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)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(World))
- {
- var start = GetByteStart(bitStart);
- Entity.PLCInfo.Ex(World).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(World))
- {
- var start = GetByteStart(bitStart);
- var bitIndex = GetBitIndex(bitStart);
- var b = Data.Skip(start).First();
- b = b.SetBit(bitIndex, flag);
- var data = new[] { b };
- Entity.PLCInfo.Ex(World).Accessor.WriteBytes(Entity.No, start, data);
- data.CopyTo(Data, start - Start);
- bitStart += 1;
- }
- }
- #endregion 写入
- }
|