DeviceExtension.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. using DBHelper;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using WCS.Core;
  6. using WCS.Entity;
  7. using WCS.Entity.Protocol;
  8. using WCS.Entity.Protocol.RGV;
  9. using WCS.Service.Helpers;
  10. namespace WCS.Service.Extensions
  11. {
  12. /// <summary>
  13. /// 输送机设备组
  14. /// </summary>
  15. public class StationDeviceGroup : DeviceGroup<IStation520, IStation521, IStation523>
  16. {
  17. public StationDeviceGroup(WCS_DEVICE entity) : base(entity)
  18. {
  19. }
  20. private List<RGVDevice> RGVs;
  21. /// <summary>
  22. /// 设备组自身的位置
  23. /// </summary>
  24. public float Position
  25. {
  26. get
  27. {
  28. return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Location;
  29. }
  30. }
  31. /// <summary>
  32. /// 设备组所在环穿的总长度
  33. /// </summary>
  34. public float Length
  35. {
  36. get
  37. {
  38. return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Length;
  39. }
  40. }
  41. /// <summary>
  42. /// 设备组是否满足任务执行条件
  43. /// </summary>
  44. /// <param name="type">给当前设备组下发任务时需要的请求</param>
  45. /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
  46. /// <exception cref="Exception"></exception>
  47. public bool WhetherToExecute(IstationRequest type = IstationRequest.无)
  48. {
  49. //当前组有一个运行的设备就停止执行
  50. if (Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) return true;
  51. //设备组中没有设备有光带信息
  52. if (!Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态))) return true;
  53. ////有光电无任务
  54. //if (Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum < 10000))
  55. // throw new Exception(LogHelper.SpliceLogMessage("有光电无任务", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
  56. ////有光电有任务无请求
  57. //if (Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum < 10000 && (type != IstationRequest.无 && v.Data2.Request != type)))
  58. // throw new Exception(LogHelper.SpliceLogMessage($"有光电有任务无 {type} 请求", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
  59. return false;
  60. }
  61. /// <summary>
  62. /// 获取设备组中需要取货的设备
  63. /// </summary>
  64. /// <param name="obj"></param>
  65. /// <returns></returns>
  66. public List<Device<IStation520, IStation521, IStation523>> RGVGetTaskedDevice()
  67. {
  68. var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
  69. .Where(v => v.Entity.CODE.ToShort() != v.Data2.Goodsend && v.Data2.Goodsend != 0)
  70. .ToList();
  71. return a.Count == 0 ? null : a;
  72. }
  73. /// <summary>
  74. /// 获取设备组中需要分配目标地址的设备
  75. /// </summary>
  76. /// <param name="obj"></param>
  77. /// <returns></returns>
  78. public List<Device<IStation520, IStation521, IStation523>> TaskedDeviceGetNextAddress()
  79. {
  80. var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
  81. .Where(v => v.Data2.Goodsend != 0)
  82. .ToList();
  83. return a.Count == 0 ? null : a;
  84. }
  85. /// <summary>
  86. ///
  87. /// </summary>
  88. /// <returns></returns>
  89. public RGVDevice NextRGV()
  90. {
  91. return new RGVDevice(new WCS_DEVICE());
  92. }
  93. /// <summary>
  94. /// 计算目标RGV与站台自身的距离
  95. /// </summary>
  96. /// <param name="rgv"></param>
  97. /// <returns></returns>
  98. public float Distance(RGVDevice rgv)
  99. {
  100. return Math.Abs((Position - rgv.Position + Length) % Length);
  101. }
  102. /// <summary>
  103. /// 当前RGV
  104. /// </summary>
  105. /// <returns></returns>
  106. public RGVDevice CurrentRGV()
  107. {
  108. return new RGVDevice(new WCS_DEVICE());
  109. }
  110. /// <summary>
  111. /// 是否需要RGV
  112. /// </summary>
  113. /// <returns>true:需要RGV false:不需要RGV</returns>
  114. public bool NeedRgv()
  115. {
  116. var rgvs = Device.Where(v => v.IsRGV()).Select(v => v.Device<IRGV521>());
  117. var code = Entity.CODE.Replace("G", "").ToShort();
  118. if (rgvs.Any(v => v.Data.DestPosition_1 == code && v.Data.SystemStatus != RGVRunStatus.空闲))
  119. throw new Exception(LogHelper.SpliceLogMessage("已有RGV执行中", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  120. foreach (var item in Items)
  121. {
  122. if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) return false;
  123. if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) return false;
  124. }
  125. return true;
  126. }
  127. }
  128. /// <summary>
  129. /// 输送机设备
  130. /// </summary>
  131. public class StationDevice : Device<IStation520, IStation521, IStation523>
  132. {
  133. public StationDevice(WCS_DEVICE entity) : base(entity)
  134. {
  135. }
  136. /// <summary>
  137. /// 设备组是否满足任务执行条件
  138. /// </summary>
  139. /// <param name="type">给当前设备组下发任务时需要的请求</param>
  140. /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
  141. /// <exception cref="Exception"></exception>
  142. public bool WhetherToExecute(IstationRequest type = IstationRequest.无)
  143. {
  144. //正在运行
  145. if (Data3.Status.HasFlag(StationStatus.运行状态位)) return true;
  146. //上一次的任务还未执行
  147. if (Data.VoucherNo != Data2.VoucherNo)
  148. throw new Exception(LogHelper.SpliceLogMessage($"等待任务[{Data2.Tasknum}]执行", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  149. //没有光电
  150. if (!Data2.Status.HasFlag(IstationStatus.光电状态)) return true;
  151. //没有任务号
  152. switch (type)
  153. {
  154. case IstationRequest.无:
  155. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  156. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  157. break;
  158. case IstationRequest.扫码入库:
  159. if (Data2.Tasknum > 10000 && Data.Tasknum > 10000)
  160. throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  161. break;
  162. case IstationRequest.堆垛机放货完成请求目标地址:
  163. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  164. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  165. break;
  166. case IstationRequest.请求分配目标地址:
  167. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  168. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  169. break;
  170. }
  171. //没有请求
  172. if (type != IstationRequest.无 && Data2.Request != type)
  173. throw new Exception(LogHelper.SpliceLogMessage($"有光电无{type}请求", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
  174. return false;
  175. }
  176. }
  177. /// <summary>
  178. /// RGV设备
  179. /// </summary>
  180. public class RGVDevice : Device<IRGV520, IRGV521, IRGV523>
  181. {
  182. static RGVDevice()
  183. {
  184. AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
  185. }
  186. public RGVDevice(WCS_DEVICE entity) : base(entity)
  187. {
  188. }
  189. /// 所有环穿RGV
  190. /// </summary>
  191. private static List<RGVDevice> AllRGVList { get; set; }
  192. /// <summary>
  193. /// 与当前RGV处于同一环穿的RGV
  194. /// </summary>
  195. public List<RGVDevice> RGVList
  196. {
  197. get
  198. {
  199. return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.ID == d.DB.ID)))
  200. .Where(v => v.Entity.CODE != Entity.CODE).ToList();
  201. }
  202. }
  203. /// <summary>
  204. /// RGV当前位置
  205. /// </summary>
  206. public float Position
  207. {
  208. get
  209. {
  210. return Data2.Position;
  211. }
  212. }
  213. /// <summary>
  214. /// 与当前RGV处于同一环穿的RGV
  215. /// </summary>
  216. public List<StationLocation> LocationList
  217. {
  218. get
  219. {
  220. return StationLocation.ALLlocations.Where(v => Entity.PROTOCOLS.Any(p => p.DB.PLC.CODE == v.PLC)).ToList();
  221. }
  222. }
  223. /// <summary>
  224. /// 总长度
  225. /// </summary>
  226. public float Length
  227. {
  228. get
  229. {
  230. return LocationList.FirstOrDefault().Length;
  231. }
  232. }
  233. /// <summary>
  234. /// 前一个RGV
  235. /// </summary>
  236. /// <returns></returns>
  237. public RGVDevice Before()
  238. {
  239. //按照位置排序
  240. var arr = RGVList.OrderBy(v => v.Position);
  241. var rgv = arr.FirstOrDefault(v => v.Position > Position);
  242. if (rgv == null)
  243. rgv = arr.LastOrDefault(v => v.Position < Position);
  244. return rgv;
  245. }
  246. /// <summary>
  247. /// 后一个RGV
  248. /// </summary>
  249. /// <returns></returns>
  250. public RGVDevice After()
  251. {
  252. var arr = RGVList.OrderBy(v => v.Position);
  253. var rgv = arr.FirstOrDefault(v => v.Position < Position);
  254. if (rgv == null)
  255. rgv = arr.LastOrDefault(v => v.Position > Position);
  256. return rgv;
  257. }
  258. /// <summary>
  259. /// 计算当前RGV与指定RGV之间的距离
  260. /// </summary>
  261. /// <param name="after"></param>
  262. /// <returns></returns>
  263. public float Distance(RGVDevice after)
  264. {
  265. return Math.Abs((Position - after.Position + Length) % Length);
  266. }
  267. /// <summary>
  268. /// 是否可用
  269. /// </summary>
  270. /// <returns></returns>
  271. public bool Valid()
  272. {
  273. return true;
  274. }
  275. /// <summary>
  276. /// 写入移动任务
  277. /// </summary>
  278. /// <param name="addr">目标地址</param>
  279. public void Move(StationDeviceGroup addr)
  280. {
  281. }
  282. /// <summary>
  283. /// 写入取货任务
  284. /// </summary>
  285. /// <param name="addr">目标地址</param>
  286. public void Pick(StationDeviceGroup addr)
  287. {
  288. }
  289. /// <summary>
  290. /// 写入放货任务
  291. /// </summary>
  292. /// <param name="addr">目标地址</param>
  293. public void Put(StationDeviceGroup addr)
  294. {
  295. }
  296. /// <summary>
  297. /// 筛选出所有与当前RGV距离小于指定长度的RGV
  298. /// </summary>
  299. /// <param name="distance">指定长度</param>
  300. /// <returns></returns>
  301. public RGVDevice[] RgvAfter(float distance)
  302. {
  303. return RGVList.Where(v => Distance(v) < distance).ToArray();
  304. }
  305. /// <summary>
  306. /// 当前RGV是否有拦住传入RGV
  307. /// </summary>
  308. /// <param name="rgv">RGV</param>
  309. /// <returns></returns>
  310. public bool StopedByMe(RGVDevice rgv)
  311. {
  312. //目标站台
  313. var target = rgv.Data2.DestPosition_1;
  314. //获取目标站台的设备组信息
  315. var station = Device.Find($"G{target}").Create<StationDeviceGroup>();
  316. //当前RGV与目标站台的距离小于传入RGV到达目标站台的距离
  317. return station.Distance(this) < station.Distance(rgv);
  318. }
  319. /// <summary>
  320. /// 获取当前RGV的下一个站台,即距离最近的一个站台
  321. /// </summary>
  322. /// <returns></returns>
  323. public StationDeviceGroup NextStation()
  324. {
  325. //先取当前RGV与所有站台的距离
  326. var dev = LocationList.OrderBy(v =>
  327. {
  328. var dev = Device.Find(v.Station).Create<StationDeviceGroup>();
  329. return dev.Distance(this);
  330. }).FirstOrDefault();
  331. return Device.Find(dev.Station).Create<StationDeviceGroup>(); ;
  332. }
  333. }
  334. /// <summary>
  335. /// 堆垛机设备
  336. /// </summary>
  337. public class SRMDevice : Device<ISRM520, ISRM521, ISRM537>
  338. {
  339. public SRMDevice(WCS_DEVICE entity) : base(entity)
  340. {
  341. }
  342. /// <summary>
  343. /// 获取放货点
  344. /// </summary>
  345. public List<StationDevice> GetDeliveryPoint()
  346. {
  347. return Entity.ROUTES.Select(v => v.NEXT) //巷道
  348. .SelectMany(v => v.ROUTES.Select(d => d.NEXT)) //放货点
  349. .Where(v => v.IsConv()) //必须是输送线
  350. .Select(v => v.Create<StationDevice>()).ToList();
  351. }
  352. /// <summary>
  353. /// 获取取货点
  354. /// </summary>
  355. public List<StationDevice> GetPickPoint()
  356. {
  357. return Device.Where(v => v.Is(DF.一楼SRM取货) || v.Is(DF.二楼SRM取货))
  358. .Where(v => v.ROUTES.Any(p => p.NEXT.ROUTES.Any(d => d.NEXT == Entity)))
  359. .Select(v => v.Create<StationDevice>())
  360. .ToList();
  361. }
  362. /// <summary>
  363. /// 处理完成任务
  364. /// </summary>
  365. public void FinishedTaskHandle()
  366. {
  367. WCS_TASK task = new WCS_TASK();
  368. DB.Do(db =>
  369. {
  370. var taskIds = new List<int>() { Data2.FinishedTask_1, Data2.FinishedTask_2 }.ToArray();
  371. for (int i = 0; i < taskIds.Length; i++)
  372. {
  373. //判断当前工位是否有完成任务
  374. if (taskIds[i] == 0) continue;
  375. //获取当前工位的目标地址
  376. var ELine = i == 0 ? Data.ELine_1.ToString() : Data.ELine_2.ToString();
  377. task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);
  378. if (task.STATUS != TaskStatus.堆垛机执行)
  379. throw new Exception(LogHelper.SpliceLogMessage($"堆垛机已完成任务[{task.ID}]但WCS状态为[{task.STATUS}],应为[{TaskStatus.堆垛机执行}]", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  380. if (task.TYPE == TaskType.入库)
  381. {
  382. task.ENDTIME = DateTime.Now;
  383. task.STATUS = TaskStatus.已完成;
  384. task.UPDATETIME = DateTime.Now;
  385. db.Default.SaveChanges();
  386. }
  387. else if (task.TYPE == TaskType.出库)
  388. {
  389. task.STATUS = TaskStatus.堆垛机完成;
  390. task.UPDATETIME = DateTime.Now;
  391. db.Default.SaveChanges();
  392. Uploader.Upload(db);
  393. var target = Device.Find(ELine).Create<StationDevice>();
  394. target.Data.Tasknum = task.ID;
  395. target.Data.Goodsstart = ELine.ToShort();
  396. target.Data.Goodsend = task.ADDRNEXT.ToShort();
  397. }
  398. else if (task.TYPE == TaskType.移库)
  399. {
  400. if (task.STATUS == TaskStatus.堆垛机执行)
  401. {
  402. task.STATUS = TaskStatus.已完成;
  403. task.UPDATETIME = DateTime.Now;
  404. db.Default.SaveChanges();
  405. Uploader.Upload(db);
  406. }
  407. }
  408. else throw new Exception($"[{Entity.CODE}]任务类型错误");
  409. if (i == 0) Data.FinishedACK_1 = 1;
  410. else Data.FinishedACK_2 = 1;
  411. task.CreateStatusLog(db, $"状态由[{TaskStatus.堆垛机执行}]变更为[{task.STATUS}]", this.GetType());
  412. }
  413. });
  414. }
  415. }
  416. /// <summary>
  417. /// 站台位置信息
  418. /// </summary>
  419. public class StationLocation
  420. {
  421. /// <summary>
  422. /// 所有环穿站台的信息
  423. /// </summary>
  424. public static List<StationLocation> ALLlocations { get; set; }
  425. static StationLocation()
  426. {
  427. ALLlocations.AddRange(new List<StationLocation>() {
  428. new StationLocation("G1187",0,"RGV1",0),
  429. new StationLocation("G1196",0,"RGV1",0),
  430. new StationLocation("G1205",0,"RGV1",0),
  431. new StationLocation("G1214",0,"RGV1",0),
  432. new StationLocation("G1222",0,"RGV1",0),
  433. new StationLocation("G1164",0,"RGV1",0),
  434. new StationLocation("G1285",0,"RGV3",0),
  435. new StationLocation("G1401",0,"RGV3",0),
  436. new StationLocation("G1294",0,"RGV3",0),
  437. new StationLocation("G1410",0,"RGV3",0),
  438. new StationLocation("G1303",0,"RGV3",0),
  439. new StationLocation("G1417",0,"RGV3",0),
  440. new StationLocation("G1412",0,"RGV3",0),
  441. new StationLocation("G1426",0,"RGV3",0),
  442. new StationLocation("G1332",0,"RGV3",0),
  443. new StationLocation("G1391",0,"RGV3",0),
  444. new StationLocation("G1399",0,"RGV3",0),
  445. });
  446. }
  447. public StationLocation(string station, int location, string plc, int length)
  448. {
  449. Station = station;
  450. Location = location;
  451. PLC = plc;
  452. Length = length;
  453. }
  454. /// <summary>
  455. /// 输送机设备组编号
  456. /// </summary>
  457. public string Station { get; set; }
  458. /// <summary>
  459. /// 输送机在环轨中的位置
  460. /// </summary>
  461. public int Location { get; set; }
  462. /// <summary>
  463. /// 所属PLC名称
  464. /// </summary>
  465. public string PLC { get; set; }
  466. /// <summary>
  467. /// 所属环穿轨道的长度
  468. /// </summary>
  469. public int Length { get; set; }
  470. }
  471. /// <summary>
  472. /// 巷道信息
  473. /// </summary>
  474. public class TunnelInfo
  475. {
  476. public WCS_DEVICE Tunnel;
  477. public WCS_DEVICE taskIN;
  478. public Device<ISRM520, ISRM521, ISRM537> SRM;
  479. }
  480. }