|
@@ -0,0 +1,456 @@
|
|
|
+using System;
|
|
|
+using System.Collections;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Reflection;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
|
+
|
|
|
+namespace WCS.Core
|
|
|
+{
|
|
|
+ public class DataBlock : EntityEx<DBInfo>
|
|
|
+ {
|
|
|
+ public event Action<byte[]> DbChanged;
|
|
|
+ public static List<DataBlock> DBList = new List<DataBlock>();
|
|
|
+
|
|
|
+ List<ProtocolProxyBase> ProxyList = new List<ProtocolProxyBase>();
|
|
|
+
|
|
|
+ public ushort Start { get; private set; }
|
|
|
+ public ushort Length { get; private set; }
|
|
|
+ bool failed = false;
|
|
|
+ byte[] Data=new byte[0];
|
|
|
+ int id = 0;
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return id.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public DataBlock(DBInfo ent) : base(ent)
|
|
|
+ {
|
|
|
+ DBList.Add(this);
|
|
|
+ id = DBList.Count;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void RefreshData()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (Length == 0)
|
|
|
+ {
|
|
|
+ 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
|
|
|
+ {
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ 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.西门子;
|
|
|
+
|
|
|
+ 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.西门子)
|
|
|
+ {
|
|
|
+ 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.PLCInfo.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);
|
|
|
+ if (Data.Length < start + length)
|
|
|
+ throw new Exception("读取数据的位置超出数据总长度");
|
|
|
+ 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.西门子;
|
|
|
+ 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.西门子)
|
|
|
+ {
|
|
|
+ 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.PLCInfo.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.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 写入
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|