using System.ComponentModel.DataAnnotations; using System.Reflection; using System.Runtime.InteropServices; namespace WCS.Core; public abstract class ProtocolProxyBase : IProtocolProxy { public DateTime ChangedTime; private byte[] Data = new byte[0]; public DateTime Frame; private readonly string Id = Guid.NewGuid().ToString(); public Dictionary Items = new(); public Type ProtocolType, ProtocolDataType; public ProtocolProxyBase(Device dev, ProtocolInfo info, Type protocolType, World world) { World = world; Frame = world.Frame; ChangedTime = world.Frame; Device = dev; Info = info; Db = info.DBInfo.Ex(world); Db.DbChanged += Db_DbChanged; ProtocolType = protocolType; var bitStart = info.Position * 8; //偏移量,按位算 //this.Start = start; //PlcDB db = new PlcDB(null, 50, 100); var lst = GetType().GetInterfaces().ToList(); var ps = lst.SelectMany(v => v.GetProperties()).ToArray(); foreach (var p in ps) { if (p.GetIndexParameters().Length > 0) continue; if (typeof(ProtocolProxyBase).GetProperty(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null) continue; #region 计算偏移量 var modeNum = 0; var t = p.PropertyType; if (t.IsEnum) t = t.GetEnumUnderlyingType(); if (t == typeof(bool)) //bit类型,db块中无须补齐16位 modeNum = 1; else if (t.IsPrimitive && Marshal.SizeOf(t) == 1) //byte char 等单字节类型,db块中无须补齐16位 modeNum = 8; else //其他类型,db块中必须补齐16位 modeNum = 16; var mod = bitStart % modeNum; if (mod > 0) bitStart += modeNum - mod; #endregion 计算偏移量 byte arrlen = 0; byte strLen = 0; if (t.IsArray) { var attr = p.GetCustomAttributes(typeof(MaxLengthAttribute), true).FirstOrDefault() as MaxLengthAttribute; if (attr != null) arrlen = (byte)attr.Length; } else if (p.PropertyType == typeof(string)) { var attr = p.GetCustomAttributes(typeof(StringLengthAttribute), true) .FirstOrDefault() as StringLengthAttribute; strLen = (byte)attr.MaximumLength; } var m = typeof(DataBlock).GetMethod("Regist"); m = m.MakeGenericMethod(p.PropertyType); var item = m.Invoke(Db, new object[] { this, Id, p.Name, bitStart, arrlen, strLen }) as PlcItem; Items.Add(p.Name, item); bitStart += item.DataSizeOfBits; BytesCount += item.DataSize; } ProtocolDataType = ProtocolType.Assembly.GetTypes().Where(v => v.IsClass || v.IsValueType) .First(v => v.GetInterface(ProtocolType.Name) != null && v != GetType()); } public ProtocolInfo Info { get; } public int BytesCount { get; } public Device Device { get; } public World World { get; } public DataBlock Db { get; } public string Code => Device.Code; private void Db_DbChanged(byte[] data) { var pos = Info.Position - Db.Start; var bytes = data.Skip(pos).Take(BytesCount).ToArray(); if (Data.SequenceEqual(bytes)) return; Frame = World.Frame; ChangedTime = World.Frame; Data = bytes; DataChanged(); } protected abstract void DataChanged(); #region public void AddEvent(string eventName, Delegate delgate) { throw new NotImplementedException(); } public void RemoveEvent(string eventName, Delegate delgate) { throw new NotImplementedException(); } public T CallReturn(string methodName, params object[] args) { throw new NotImplementedException(); } public void CallVoid(string methodName, params object[] args) { throw new NotImplementedException(); } public T Get(string propertyName) { var item = Items[propertyName] as PlcItem; var res = item.Value; var channel = Ltc.GetChannel(); return res; } public void Set(string propertyName, T value) { var item = Items[propertyName] as PlcItem; item.Value = value; var channel = Ltc.GetChannel(); if (channel != null)World.OnInternalLog(channel, $"设置值:设置{Device.Code}.{ProtocolType.Name}.{propertyName} 值:{value}"); Frame = World.Frame; ChangedTime = World.Frame; DataChanged(); } #endregion }