using System.ComponentModel.DataAnnotations; using System.Reflection; using System.Runtime.InteropServices; namespace WCS.Core { public abstract class ProtocolProxyBase : IProtocolProxy { private string Id = Guid.NewGuid().ToString(); public ProtocolInfo Info { get; private set; } public ushort BytesCount { get; private set; } public Dictionary Items = new Dictionary(); public Type ProtocolType, ProtocolDataType; public Device Device { get; private set; } public World World { get; private set; } private DataBlock Db; public ProtocolProxyBase(Device dev, ProtocolInfo info, Type protocolType, World world) { this.World = world; this.Device = dev; this.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 = this.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).First(v => v.GetInterface(ProtocolType.Name) != null && v != this.GetType()); } private byte[] Data = new byte[0]; 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; 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(); if (channel != null) this.World.OnInternalLog(channel, $"获取值:{Device.Code}.{ProtocolType.Name}.{propertyName}:{res}"); return res; } public void Set(string propertyName, T value) { var item = Items[propertyName] as PlcItem; item.Value = value; var channel = Ltc.GetChannel(); this.World.OnInternalLog(channel, $"设置值:{Device.Code}.{ProtocolType.Name}.{propertyName} :{value}"); } #endregion } }