DeviceExtension.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. using PlcSiemens.Core.Extension;
  2. using ServiceCenter.Extensions;
  3. using ServiceCenter.Logs;
  4. using ServiceCenter.Redis;
  5. using WCS.Core;
  6. using WCS.Entity.Protocol.BCR;
  7. using WCS.Entity.Protocol.Protocol.Robot;
  8. using WCS.Entity.Protocol.Robot;
  9. using WCS.Entity.Protocol.Station;
  10. using WCS.Entity.Protocol.Truss;
  11. namespace WCS.WorkEngineering.Extensions
  12. {
  13. /// <summary>
  14. /// 设备扩展
  15. /// </summary>
  16. public static class DeviceExtension
  17. {
  18. #region 设备类型
  19. public static List<ProtocolInfo> ProtocolInfos = new List<ProtocolInfo>();
  20. /// <summary>
  21. /// 是否是巷道
  22. /// </summary>
  23. /// <param name="source">设备信息</param>
  24. /// <returns></returns>
  25. public static bool IsTunnel(this Device source)
  26. {
  27. return source.HasFlag(DeviceFlags.巷道);
  28. }
  29. #endregion 设备类型
  30. #region 标签判断
  31. public static bool HasFlag(this Device device, params DeviceFlags[] flag)
  32. {
  33. return flag.Any(device.HasFlag);
  34. }
  35. #endregion 标签判断
  36. #region 协议操作扩展
  37. public static void AddProtocol<T>(this Device device, int position, ushort db, string ip)
  38. {
  39. var info = new ProtocolInfo
  40. {
  41. Position = position,
  42. DBInfo = new DBInfo
  43. {
  44. No = db,
  45. PLCInfo = new PLCInfo
  46. {
  47. IP = ip,
  48. Port = 102,
  49. Rack = 0,
  50. Slot = 1,
  51. Type = PLCType.Siemens
  52. }
  53. }
  54. };
  55. ProtocolInfos.Add(info);
  56. device.AddProtocol<T>(info);
  57. }
  58. #endregion 协议操作扩展
  59. #region 设备扩展方法
  60. /// <summary>
  61. /// 入库站点是否被禁止
  62. /// </summary>
  63. /// <returns></returns>
  64. public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523> device)
  65. {
  66. var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
  67. var configs = config.Split(",");
  68. if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用,请联系运维人员了解具体情况", LogLevelEnum.High);
  69. }
  70. /// <summary>
  71. /// 入库站点是否被禁止
  72. /// </summary>
  73. /// <returns></returns>
  74. public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IBCR81> device)
  75. {
  76. var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
  77. var configs = config.Split(",");
  78. if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用,请联系运维人员了解具体情况", LogLevelEnum.High);
  79. }
  80. /// <summary>
  81. /// 入库站点是否被禁止
  82. /// </summary>
  83. /// <returns></returns>
  84. public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IStation91> device)
  85. {
  86. var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
  87. var configs = config.Split(",");
  88. if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用,请联系运维人员了解具体情况", LogLevelEnum.High);
  89. }
  90. /// <summary>
  91. /// 入库站点是否被禁止
  92. /// </summary>
  93. /// <returns></returns>
  94. public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IStation91, IBCR81> device)
  95. {
  96. var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
  97. var configs = config.Split(",");
  98. if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用,请联系运维人员了解具体情况", LogLevelEnum.High);
  99. }
  100. /// <summary>
  101. /// 入库站点是否满足执行条件
  102. /// </summary>
  103. /// <returns></returns>
  104. public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523> device)
  105. {
  106. if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
  107. if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
  108. if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
  109. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
  110. if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
  111. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
  112. if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
  113. }
  114. /// <summary>
  115. /// 入库站点是否满足执行条件
  116. /// </summary>
  117. /// <returns></returns>
  118. public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IBCR81> device)
  119. {
  120. if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
  121. if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
  122. if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
  123. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
  124. if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
  125. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
  126. if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
  127. }
  128. /// <summary>
  129. /// 入库站点是否满足执行条件
  130. /// </summary>
  131. /// <returns></returns>
  132. public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IStation91> device)
  133. {
  134. if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
  135. if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
  136. if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
  137. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
  138. if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
  139. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
  140. if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
  141. }
  142. /// <summary>
  143. /// 入库站点是否满足执行条件
  144. /// </summary>
  145. /// <returns></returns>
  146. public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IStation91, IBCR81> device)
  147. {
  148. if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
  149. if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
  150. if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
  151. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
  152. if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
  153. if (device.Data2.Request != 1.ToShort()) throw new KnownException("无请求", LogLevelEnum.Mid);
  154. if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
  155. if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
  156. }
  157. /// <summary>
  158. /// 获取BCR码
  159. /// </summary>
  160. /// <returns></returns>
  161. public static string GetBCRCode(this IBCR81 bCR)
  162. {
  163. var barcode = bCR.Content.Trim('\0');
  164. if (barcode.IsNullOrWhiteSpace()) throw new KnownException($"扫码失败,内容为空", LogLevelEnum.High);
  165. return barcode;
  166. }
  167. /// <summary>
  168. /// 获取历史扫码记录
  169. /// </summary>
  170. /// <returns></returns>
  171. public static List<string> GetBcrCodeList(this IBCR83 bCR)
  172. {
  173. return new List<string>() {
  174. bCR.BcrCode1.Trim('\0').Trim(),
  175. bCR.BcrCode2.Trim('\0').Trim(),
  176. bCR.BcrCode3.Trim('\0').Trim(),
  177. bCR.BcrCode4.Trim('\0').Trim(),
  178. bCR.BcrCode5.Trim('\0').Trim(),
  179. bCR.BcrCode6.Trim('\0').Trim(),
  180. bCR.BcrCode7.Trim('\0').Trim(),
  181. bCR.BcrCode8.Trim('\0').Trim(),
  182. bCR.BcrCode9.Trim('\0').Trim(),
  183. bCR.BcrCode10.Trim('\0').Trim(),
  184. bCR.BcrCode11.Trim('\0').Trim() };
  185. }
  186. /// <summary>
  187. /// 获取缓存列表
  188. /// </summary>
  189. /// <returns></returns>
  190. public static IEnumerable<string> GetBcrCodeList(this IStation525 station525)
  191. {
  192. var properties = station525.GetType().GetProperties().ToArray();
  193. var index = 1;
  194. for (var i = 1; i <= 50; i++)
  195. {
  196. var value = properties[index].GetValue(station525).ToString().Trim('\0').Trim();
  197. if (!value.IsNullOrEmpty()) yield return value;
  198. index += 7;
  199. }
  200. }
  201. /// <summary>
  202. /// 获取缓存列表
  203. /// </summary>
  204. /// <returns></returns>
  205. public static IEnumerable<int> GetTaskNoList(this ITruss531 station525)
  206. {
  207. var properties = station525.GetType().GetProperties().ToArray();
  208. var index = 0;
  209. for (var i = 0; i <= 59; i++)
  210. {
  211. var value = properties[index].GetValue(station525)!.ToInt();
  212. if (value > 0) yield return value;
  213. index += 1;
  214. }
  215. }
  216. /// <summary>
  217. /// 获取缓存列表
  218. /// </summary>
  219. /// <returns></returns>
  220. public static IEnumerable<int> GetTaskNoList(this IRobot531 station525)
  221. {
  222. var properties = station525.GetType().GetProperties().ToArray();
  223. var index = 0;
  224. for (var i = 0; i <= 29; i++)
  225. {
  226. var value = properties[index].GetValue(station525)!.ToInt();
  227. if (value > 0) yield return value;
  228. index += 1;
  229. }
  230. }
  231. /// <summary>
  232. /// 通过仓库编码获取对应堆垛机信息
  233. /// </summary>
  234. /// <param name="warehouseCode">仓库编码</param>
  235. /// <returns></returns>
  236. public static string WarehouseToSrm(this string warehouseCode)
  237. {
  238. return warehouseCode switch
  239. {
  240. "1N" => "SRM1",
  241. "1S" => "SRM2",
  242. "2N" => "SRM3",
  243. "2S" => "SRM4",
  244. "3N" => "SRM5",
  245. "3S" => "SRM6",
  246. _ => "Error"
  247. };
  248. }
  249. #endregion 设备扩展方法
  250. /// <summary>
  251. /// 获取仓库号
  252. /// </summary>
  253. public static string GetWareCode(this string add)
  254. {
  255. return add switch
  256. {
  257. "2532" => "1N",
  258. "2527" => "1N",
  259. "2528" => "1N",
  260. "2732" => "1S",
  261. "2727" => "1S",
  262. "2728" => "1S",
  263. "1606" => "1N",
  264. "1666" => "1NR",
  265. "SRM1" => "1N",
  266. "SRM2" => "2N",
  267. _ => "",
  268. };
  269. }
  270. }
  271. /// <summary>
  272. /// 设备标签
  273. /// </summary>
  274. [Flags]
  275. public enum DeviceFlags : ulong
  276. {
  277. 扫码 = 1L << 0,
  278. 称重 = 1L << 1,
  279. 外检 = 1L << 2,
  280. 顶升 = 1L << 3,
  281. 移栽 = 1L << 4,
  282. 旋转 = 1L << 5,
  283. 入库 = 1L << 6,
  284. 出库 = 1L << 7,
  285. 巷道口 = 1L << 8,
  286. RGV口 = 1L << 9,
  287. AGV取货站台口 = 1L << 10,
  288. 直轨 = 1L << 11,
  289. 弯轨 = 1L << 12,
  290. 环轨 = 1L << 13,
  291. 巷道 = 1L << 14,
  292. 堆垛机 = 1L << 15,
  293. 输送机 = 1L << 16,
  294. #region 一轨双车堆垛机
  295. 一列堆垛机 = 1L << 23,
  296. 二列堆垛机 = 1L << 24,
  297. #endregion 一轨双车堆垛机
  298. RGV = 1L << 25,
  299. 桁架 = 1L << 26,
  300. 一楼扫码 = 1L << 27,
  301. 满轮主线第一次扫码 = 1L << 28,
  302. 主线分流点 = 1L << 29,
  303. 一楼叠盘机 = 1L << 30,
  304. 环形库分流点 = 1L << 31,
  305. 桁架分流点 = 1L << 32,
  306. 桁架缓存放行点 = 1L << 33,
  307. 桁架取货点 = 1L << 34,
  308. 拆盘机09 = 1L << 35,
  309. 拆盘机非09 = 1L << 36,
  310. 桁架码垛位 = 1L << 37,
  311. 环形库码垛工位 = 1L << 38,
  312. Robot = 1L << 39
  313. }
  314. /// <summary>
  315. /// 输送机段信息
  316. /// </summary>
  317. public class StationSegmentInfo
  318. {
  319. /// <summary>
  320. /// 构造函数
  321. /// </summary>
  322. /// <param name="start">起始设备号</param>
  323. /// <param name="end">结束设备号</param>
  324. /// <param name="ip">ip</param>
  325. public StationSegmentInfo(int start, int end, string ip)
  326. {
  327. Start = start;
  328. End = end;
  329. Ip = ip;
  330. }
  331. /// <summary>
  332. /// 起始设备编号
  333. /// </summary>
  334. public int Start { get; set; }
  335. /// <summary>
  336. ///结束设备编号
  337. /// </summary>
  338. public int End { get; set; }
  339. /// <summary>
  340. /// 输送机段所属IP
  341. /// </summary>
  342. public string Ip { get; set; }
  343. }
  344. /// <summary>
  345. /// RGV信息
  346. /// </summary>
  347. public class RgvSegmentInfo
  348. {
  349. /// <summary>
  350. /// 构造函数
  351. /// </summary>
  352. /// <param name="code"></param>
  353. /// <param name="ip">ip</param>
  354. public RgvSegmentInfo(int code, string ip)
  355. {
  356. Code = code;
  357. Ip = ip;
  358. }
  359. /// <summary>
  360. /// 设备编号
  361. /// </summary>
  362. public int Code { get; set; }
  363. /// <summary>
  364. /// 输送机段所属IP
  365. /// </summary>
  366. public string Ip { get; set; }
  367. }
  368. /// <summary>
  369. /// 桁架信息
  370. /// </summary>
  371. public class TrussSegmentInfo
  372. {
  373. /// <summary>
  374. /// 构造函数
  375. /// </summary>
  376. /// <param name="code"></param>
  377. /// <param name="ip">ip</param>
  378. public TrussSegmentInfo(int code, string ip)
  379. {
  380. Code = code;
  381. Ip = ip;
  382. }
  383. /// <summary>
  384. /// 设备编号
  385. /// </summary>
  386. public int Code { get; set; }
  387. /// <summary>
  388. /// 输送机段所属IP
  389. /// </summary>
  390. public string Ip { get; set; }
  391. }
  392. /// <summary>
  393. /// 扫码器信息
  394. /// </summary>
  395. public class BcrInfo
  396. {
  397. /// <summary>
  398. /// 构造函数
  399. /// </summary>
  400. /// <param name="deviceNo">设备编号</param>
  401. /// <param name="ip">ip</param>
  402. public BcrInfo(string[] deviceNo, string ip)
  403. {
  404. DeviceNo = deviceNo;
  405. Ip = ip;
  406. }
  407. /// <summary>
  408. /// 设备编号
  409. /// </summary>
  410. public string[] DeviceNo { get; set; }
  411. /// <summary>
  412. /// ip
  413. /// </summary>
  414. public string Ip { get; set; }
  415. }
  416. /// <summary>
  417. /// 外形信息
  418. /// </summary>
  419. public class ShapeInfo
  420. {
  421. /// <summary>
  422. /// 构造函数
  423. /// </summary>
  424. /// <param name="deviceNo">设备编号</param>
  425. /// <param name="ip">ip</param>
  426. public ShapeInfo(int[] deviceNo, string ip)
  427. {
  428. DeviceNo = deviceNo;
  429. Ip = ip;
  430. }
  431. /// <summary>
  432. /// 设备编号
  433. /// </summary>
  434. public int[] DeviceNo { get; set; }
  435. /// <summary>
  436. /// ip
  437. /// </summary>
  438. public string Ip { get; set; }
  439. }
  440. /// <summary>
  441. /// 路径信息
  442. /// </summary>
  443. public class RouteInfo
  444. {
  445. /// <summary>
  446. /// 构造函数
  447. /// </summary>
  448. /// <param name="deviceCode">起始点设备号</param>
  449. /// <param name="nextList">下一个设备集合</param>
  450. public RouteInfo(string deviceCode, string[] nextList)
  451. {
  452. DeviceCode = deviceCode;
  453. NextList = nextList;
  454. }
  455. /// <summary>
  456. /// 设备号
  457. /// </summary>
  458. public string DeviceCode { get; set; }
  459. /// <summary>
  460. /// 下一个设备
  461. /// </summary>
  462. public string[] NextList { get; set; }
  463. }
  464. /// <summary>
  465. /// 缓存分流信息
  466. /// </summary>
  467. public class CacheBcr
  468. {
  469. public CacheBcr(string bcrCode, short nextAdd)
  470. {
  471. BcrCode = bcrCode;
  472. NextAdd = nextAdd;
  473. }
  474. /// <summary>
  475. /// 条码
  476. /// </summary>
  477. public string BcrCode { get; set; }
  478. /// <summary>
  479. /// 下一个地址
  480. /// </summary>
  481. public short NextAdd { get; set; }
  482. }
  483. }