ProtocolProxyBase.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. using DbHelper;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel.DataAnnotations;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Runtime.InteropServices;
  8. using System.Threading.Tasks;
  9. using WCS.Entity;
  10. namespace WCS.Core.DataTrans
  11. {
  12. /// <summary>
  13. /// IL动态生成的类型所继承的基类
  14. /// </summary>
  15. public abstract class ProtocolProxyBase : IProtocolProxy
  16. {
  17. protected Type ProtocolType, ProtocolDataType;
  18. public static Func<WCS_PROTOCOLDATA, string, WCS_PROTOCOLDATA> DataChanged;
  19. private readonly Dictionary<string, PlcItem> _items = new Dictionary<string, PlcItem>();
  20. public string Id { get; set; }
  21. public WCS_DEVICEPROTOCOL Protocol { get; private set; }
  22. /// <summary>
  23. /// 起始便宜量,按字节算
  24. /// </summary>
  25. public readonly ushort _start;
  26. /// <summary>
  27. /// 长度,按字节算
  28. /// </summary>
  29. public readonly ushort _length;
  30. public WCS_DATABLOCK Db;
  31. private static readonly Dictionary<Type, object> LockObjs = new Dictionary<Type, object>();
  32. protected ProtocolProxyBase(string id, WCS_DATABLOCK db, ushort start, WCS_DEVICEPROTOCOL deviceItem)
  33. {
  34. var type = this.GetType();
  35. if (!LockObjs.ContainsKey(type))
  36. LockObjs[type] = new object();
  37. this.Db = db;
  38. db.Ex().DataChanged += PLCData_DataChanged;
  39. this._start = start;
  40. var bitStart = start * 8;//偏移量,按位算
  41. this.Id = id;
  42. this.Protocol = deviceItem;
  43. var lst = this.GetType().GetInterfaces().ToList();
  44. var ps = lst.SelectMany(v => v.GetProperties()).ToArray();
  45. foreach (var p in ps)
  46. {
  47. if (p.GetIndexParameters().Length > 0)
  48. continue;
  49. if (typeof(ProtocolProxyBase).GetProperty(p.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null)
  50. {
  51. continue;
  52. }
  53. #region 计算偏移量
  54. var modeNum = 0;
  55. var t = p.PropertyType;
  56. if (t.IsEnum)
  57. t = t.GetEnumUnderlyingType();
  58. if (t == typeof(bool))//bit类型,db块中无须补齐16位
  59. {
  60. modeNum = 1;
  61. }
  62. else if (t.IsPrimitive && Marshal.SizeOf(t) == 1)//byte char 等单字节类型,db块中无须补齐16位
  63. {
  64. modeNum = 8;
  65. }
  66. else//其他类型,db块中必须补齐16位
  67. {
  68. modeNum = 16;
  69. }
  70. var mod = bitStart % modeNum;
  71. if (mod > 0)
  72. {
  73. bitStart += modeNum - mod;
  74. }
  75. #endregion 计算偏移量
  76. byte arrlen = 0;
  77. byte strLen = 0;
  78. if (t.IsArray)
  79. {
  80. var attr = p.GetCustomAttributes(typeof(MaxLengthAttribute), true).FirstOrDefault() as MaxLengthAttribute;
  81. if (attr != null)
  82. arrlen = (byte)attr.Length;
  83. }
  84. else if (p.PropertyType == typeof(string))
  85. {
  86. var attr = p.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault() as StringLengthAttribute;
  87. strLen = (byte)attr.MaximumLength;
  88. }
  89. var m = typeof(DataBlock).GetMethod("Regist");
  90. m = m.MakeGenericMethod(p.PropertyType);
  91. var item = m.Invoke(db.Ex(), new object[] { this.Id, p.Name, bitStart, arrlen, strLen }) as PlcItem;
  92. _items.Add(p.Name, item);
  93. bitStart += item.DataSizeOfBits;
  94. _length += item.DataSize;
  95. }
  96. ProtocolType = this.Protocol.DB.GetProtocolType();
  97. ProtocolDataType = ProtocolType.Assembly.GetTypes().Where(v => v.IsClass).First(v => v.GetInterface(ProtocolType.Name) != null && v != this.GetType());
  98. }
  99. private byte[] Data = null;
  100. private static object _locobj = new object();
  101. private void InvokeUpdate(string user, Db db)
  102. {
  103. //TODO:怀疑会有问题,需要再看一下
  104. Task.Run(() =>
  105. {
  106. SaveChangs(user, db);
  107. });
  108. }
  109. private WCS_PROTOCOLDATA _last = null;
  110. public DateTime UpdateTime;
  111. protected virtual void SaveChangs(string user, Db db)
  112. {
  113. var obj = Copy(this, ProtocolDataType) as WCS_PROTOCOLDATA;
  114. obj!.WCSVERSION = this.WcsVersion;
  115. if (_last == null)
  116. {
  117. Publish(this.Protocol.DEVICE.CODE, obj);
  118. _last = GetLastData(db);
  119. }
  120. if (_last != null)
  121. {
  122. if (Equals(obj, _last, ProtocolType))
  123. return;
  124. }
  125. this.UpdateTime = DateTime.Now;
  126. Publish(this.Protocol.DEVICE.CODE, obj);
  127. _last = SaveNewData(db, _last, obj, user);
  128. }
  129. public virtual void Publish(string code, WCS_PROTOCOLDATA obj)
  130. {
  131. }
  132. protected abstract WCS_PROTOCOLDATA GetLastData(Db db);
  133. protected abstract WCS_PROTOCOLDATA SaveNewData(Db db, WCS_PROTOCOLDATA last, WCS_PROTOCOLDATA newobj, string user);
  134. private void PLCData_DataChanged(Db db, byte[] data)
  135. {
  136. var temp = data.Skip(_start).Take(_length).ToArray();
  137. try
  138. {
  139. if (Data != null && Data.SequenceEqual(temp))
  140. return;
  141. var d1 = DateTime.Now;
  142. InvokeUpdate("PLC", db);
  143. var d = (DateTime.Now - d1).TotalMilliseconds;
  144. }
  145. finally { Data = temp; }
  146. }
  147. private static object Copy(object obj, Type type)
  148. {
  149. var res = Activator.CreateInstance(type);
  150. foreach (var p in type.GetProperties())
  151. {
  152. var p2 = obj.GetType().GetProperty(p.Name);
  153. if (p2 != null && p2.PropertyType == p.PropertyType)
  154. {
  155. p.SetValue(res, p2.GetValue(obj));
  156. }
  157. }
  158. return res;
  159. }
  160. private static bool Equals(object a, object b, Type type)
  161. {
  162. foreach (var p in type.GetProperties())
  163. {
  164. var v1 = p.GetValue(a);
  165. var v2 = p.GetValue(b);
  166. var attr = p.GetCustomAttribute<IgnoreChangingAttribute>();
  167. if (attr != null)
  168. {
  169. if (attr.IgnoreValueRange == 0)
  170. continue;
  171. try
  172. {
  173. var d = Math.Abs((decimal.Parse(v1.ToString())) - (decimal.Parse(v2.ToString())));
  174. if (d < attr.IgnoreValueRange)
  175. continue;
  176. }
  177. catch
  178. {
  179. Console.WriteLine("IgnoreValueRange属性只能用于数字类型");
  180. }
  181. }
  182. if (p.PropertyType == typeof(string))
  183. {
  184. v1 = v1 == null ? "" : v1.ToString();
  185. v2 = v2 == null ? "" : v2.ToString();
  186. }
  187. if (p.PropertyType.IsArray)
  188. {
  189. var m = typeof(Enumerable).GetMethods().Where(v => v.Name == nameof(Enumerable.SequenceEqual)).First(v => v.GetParameters().Length == 2);
  190. m = m.MakeGenericMethod(p.PropertyType.GetElementType()!);
  191. var res = (bool)m.Invoke(null, new[] { v1, v2 })!;
  192. if (!res)
  193. return false;
  194. }
  195. else
  196. {
  197. if (!v1!.Equals(v2))
  198. return false;
  199. }
  200. }
  201. return true;
  202. }
  203. #region IGenerator
  204. /// <summary>
  205. /// 索引器Get
  206. /// </summary>
  207. /// <typeparam name="T"></typeparam>
  208. /// <param name="args"></param>
  209. /// <returns></returns>
  210. protected T GetItem<T>(params object[] args)
  211. {
  212. Console.WriteLine("GetItem:" + string.Join(",", args.Select(v => v.ToString())));
  213. return default(T);
  214. }
  215. /// <summary>
  216. /// 索引器Set
  217. /// </summary>
  218. /// <param name="args"></param>
  219. /// <returns></returns>
  220. protected void SetItem(params object[] args)
  221. {
  222. Console.WriteLine("SetItem:" + ":" + string.Join(",", args.Select(v => v.ToString())));
  223. }
  224. /// <summary>
  225. /// 版本号,WCS每修改一次数据,版本号变化一次
  226. /// </summary>
  227. public int WcsVersion { get; private set; }
  228. public void Set<T>(string propertyName, T value)
  229. {
  230. var str = Protocol.DEVICE.CODE + "." + ProtocolType.Name + "." + propertyName;
  231. try
  232. {
  233. str += " = " + (value == null ? "null" : value.ToString());
  234. var item = _items[propertyName] as PlcItem<T>;
  235. item.Value = value;
  236. DbHelper.Db.Do(db =>
  237. {
  238. InvokeUpdate("WCS", db);
  239. });
  240. Data = null;
  241. WcsVersion++;
  242. str += " 写入成功";
  243. }
  244. catch
  245. {
  246. str += " 写入失败";
  247. throw;
  248. }
  249. finally
  250. {
  251. Ltc.Log(str);
  252. }
  253. }
  254. public void Update(string prop, object value, string user)
  255. {
  256. var item = _items[prop];
  257. item.Value = value;
  258. DbHelper.Db.Do(db =>
  259. {
  260. InvokeUpdate(user, db);
  261. });
  262. Data = null;
  263. if (user == "PLC")
  264. return;
  265. WcsVersion++;
  266. }
  267. public T Get<T>(string propertyName)
  268. {
  269. var str = Protocol.DEVICE.CODE + "." + ProtocolType.Name + "." + propertyName;
  270. try
  271. {
  272. var item = _items[propertyName] as PlcItem<T>;
  273. var res = item.Value;
  274. str += " : " + (res == null ? "null" : res.ToString());
  275. return res;
  276. }
  277. catch
  278. {
  279. str += " 读取失败";
  280. throw;
  281. }
  282. }
  283. public T CallReturn<T>(string methodName, params object[] args)
  284. {
  285. Console.WriteLine(methodName + ":" + string.Join(",", args.Select(v => v.ToString())));
  286. return (T)(object)1.321f;
  287. }
  288. public void CallVoid(string methodName, params object[] args)
  289. {
  290. Console.WriteLine(methodName + ":" + string.Join(",", args.Select(v => v.ToString())));
  291. }
  292. public void AddEvent(string eventName, Delegate delgate)
  293. {
  294. Console.WriteLine("Add:" + eventName);
  295. }
  296. public void RemoveEvent(string eventName, Delegate delgate)
  297. {
  298. Console.WriteLine("Remove:" + eventName);
  299. }
  300. #endregion IGenerator
  301. public override string ToString()
  302. {
  303. var str = this.GetType().GetProperties().Aggregate("", (current, p) => current + (p.Name + ":" + p.GetValue(this, null)!.ToString() + ","));
  304. str = str[..^1];
  305. return str;
  306. }
  307. }
  308. }