PackControlCrms.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. using ProjectManagementSystem.Common.Config;
  2. using ProjectManagementSystem.Common.Extenions;
  3. using ProjectManagementSystem.Common.Function;
  4. using ProjectManagementSystem.Common.Logger;
  5. using ProjectManagementSystem.Common.Models;
  6. using ProjectManagementSystem.Common.Models.Crms;
  7. using ProjectManagementSystem.Common.Service;
  8. using System;
  9. using System.Collections.Concurrent;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. namespace ProjectManagementSystem.Common.Core
  15. {
  16. public class PackControlCrms
  17. {
  18. private static PackControlCrms m_instance;
  19. private bool firstStart = true;
  20. private bool agvHeartbeat;
  21. private uint counter;
  22. private bool[] forceWrite = new bool[20];
  23. public double TimeConsumption { get; private set; }
  24. public ConcurrentDictionary<string, PackStationV2> StationDictionary { get; set; } = new ConcurrentDictionary<string, PackStationV2>();
  25. public static PackControlCrms Instance
  26. {
  27. get
  28. {
  29. if (m_instance == null)
  30. {
  31. m_instance = new PackControlCrms();
  32. if (!m_instance.Initialize())
  33. {
  34. m_instance = null;
  35. }
  36. }
  37. return m_instance;
  38. }
  39. }
  40. private PackControlCrms()
  41. {
  42. }
  43. private bool Initialize()
  44. {
  45. try
  46. {
  47. var assemblyName = this.GetType().Assembly.GetName().Name;
  48. var nameSpace = this.GetType().Namespace;
  49. string fullClassName = $"{nameSpace}.PackInteractionCrmsBase";
  50. var packInteration = InstanceConstructor.GetInstance<IPackInteractionCrms>(assemblyName, fullClassName);
  51. if (packInteration == null)
  52. {
  53. throw new NullReferenceException("创建的对象为null");
  54. }
  55. var configList = ExcelConfig.Instance.RouteConfigList;
  56. for (int i = 0; i < configList.Count; i++)
  57. {
  58. var config = configList[i];
  59. var data = StationDictionary.TryGetValue(config.LocationCode, out var station) ? station : new PackStationV2();
  60. data.Id = config.LocationCode;
  61. data.Config = config;
  62. var sClassName = config.LocationCode.GetLocationMember("PACK对接类");
  63. if (!string.IsNullOrEmpty(sClassName))
  64. {
  65. var sPackInteraction = InstanceConstructor.GetInstance<IPackInteractionCrms>(assemblyName, $"{nameSpace}.{sClassName}");
  66. if (sPackInteraction == null)
  67. {
  68. throw new NullReferenceException("创建的对象为null");
  69. }
  70. data.Interaction = sPackInteraction;
  71. }
  72. else
  73. {
  74. data.Interaction = packInteration;
  75. }
  76. StationDictionary.AddOrUpdate(data.Id, data, (key, value) => data);
  77. }
  78. Task.Factory.StartNew(UserThread, TaskCreationOptions.LongRunning);
  79. return true;
  80. }
  81. catch (Exception ex)
  82. {
  83. CLog.Instance.SystemLog.WriteException("PackControl Initialize", ex);
  84. }
  85. return false;
  86. }
  87. private void UpdateStationDict()
  88. {
  89. var packStationInfos = Crms.PmsApi.GetPackStationAGVAll();
  90. if (packStationInfos == null)
  91. {
  92. Thread.Sleep(5000);
  93. return;
  94. }
  95. var agvDataList = Crms.PmsApi.GetAllCarrier();
  96. if (agvDataList == null) return;
  97. var taskList = Crms.PmsApi.GetTaskList();
  98. if (taskList == null) return;
  99. var agvDataOnlineList = agvDataList.Where(d => d.Online);
  100. var agvDataDict = agvDataList.ToDictionary(d => d.AgvID);
  101. var packStationInfoDict = packStationInfos.ToDictionary(d => d.id);
  102. foreach (var item in packStationInfos)
  103. {
  104. if (item.carrierPackStatuses != null)
  105. {
  106. foreach (var item2 in item.carrierPackStatuses)
  107. {
  108. agvDataDict.TryGetValue(item2.carrier, out var agvData);
  109. item2.AgvData = agvData ?? null;
  110. }
  111. }
  112. }
  113. var callHeartbeat = counter % 2 == 0;
  114. if (callHeartbeat)
  115. {
  116. agvHeartbeat = !agvHeartbeat;
  117. }
  118. DateTime start = DateTime.Now;
  119. Parallel.ForEach(StationDictionary.Values, delegate (PackStationV2 data, ParallelLoopState loopState)
  120. {
  121. try
  122. {
  123. if (callHeartbeat)
  124. {
  125. data.Interaction.Heartbeat(data, agvHeartbeat);
  126. }
  127. packStationInfoDict.TryGetValue(data.Id, out var packStationInfo);
  128. data.AgvList = packStationInfo?.carrierPackStatuses;
  129. //工位AGV状态变化
  130. if (data.AgvList?.Count > 0)
  131. {
  132. foreach (var item in data.AgvList)
  133. {
  134. var lastItem = data.LastAgvList?.FirstOrDefault(d => d.carrier == item.carrier);
  135. if (item.agvPositionStatus != lastItem?.agvPositionStatus)
  136. {
  137. data.Interaction.AgvPositionStatusChanged(data, item, lastItem, taskList);
  138. }
  139. if (item.agvStationStatus != lastItem?.agvStationStatus)
  140. {
  141. data.Interaction.AgvStationStatusChanged(data, item, lastItem, taskList);
  142. }
  143. }
  144. }
  145. else if (data.LastAgvList?.Count > 0)
  146. {
  147. foreach (var lastItem in data.LastAgvList)
  148. {
  149. data.Interaction.AgvPositionStatusChanged(data, null, lastItem, taskList);
  150. data.Interaction.AgvStationStatusChanged(data, null, lastItem, taskList);
  151. }
  152. }
  153. data.LastAgvList = data.AgvList;
  154. //小车数据
  155. data.AgvApproachingData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.BeforeRequest);
  156. data.AgvRequestEnterData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.RequestVertex);
  157. data.AgvEnteringData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.Entering);
  158. data.AgvAtStationData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.StationVertex);
  159. data.AgvLeavingData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.Leaving);
  160. data.AgvLeaveDoneData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.ReleaseVertex);
  161. data.AgvIdApproaching = data.AgvApproachingData?.carrier ?? 0;
  162. data.AgvIdRequestEnter = data.AgvRequestEnterData?.carrier ?? 0;
  163. data.AgvIdEntering = data.AgvEnteringData?.carrier ?? 0;
  164. data.AgvIdAtStation = data.AgvAtStationData?.carrier ?? 0;
  165. data.AgvIdLeaving = data.AgvLeavingData?.carrier ?? 0;
  166. data.AgvIdLeaveDone = data.AgvLeaveDoneData?.carrier ?? 0;
  167. data.Interaction.CustomProcess(data, firstStart, forceWrite);
  168. //工位AGV状态对接
  169. if (data.AgvList != null)
  170. {
  171. foreach (var item in data.AgvList)
  172. {
  173. switch (item.agvStationStatus)
  174. {
  175. case EPackAgvStationStatus.None:
  176. break;
  177. case EPackAgvStationStatus.WaitTask:
  178. data.Interaction.WaitTask(data, item, taskList);
  179. break;
  180. case EPackAgvStationStatus.WaitEnter:
  181. data.Interaction.WaitEnter(data, item, taskList);
  182. break;
  183. case EPackAgvStationStatus.AtRequest:
  184. data.Interaction.AtRequest(data, item, taskList);
  185. break;
  186. case EPackAgvStationStatus.WaitRequest:
  187. data.Interaction.WaitRequest(data, item, taskList);
  188. break;
  189. case EPackAgvStationStatus.Entering:
  190. data.Interaction.Entering(data, item, taskList);
  191. break;
  192. case EPackAgvStationStatus.AtStation:
  193. data.Interaction.AtStation(data, item, taskList);
  194. break;
  195. case EPackAgvStationStatus.WaitStation:
  196. data.Interaction.WaitStation(data, item, taskList);
  197. break;
  198. case EPackAgvStationStatus.Leaving:
  199. data.Interaction.Leaving(data, item, taskList);
  200. break;
  201. case EPackAgvStationStatus.AtLeave:
  202. data.Interaction.AtLeave(data, item, taskList);
  203. break;
  204. case EPackAgvStationStatus.WaitLeave:
  205. data.Interaction.WaitLeave(data, item, taskList);
  206. break;
  207. default:
  208. break;
  209. }
  210. }
  211. }
  212. data.Interaction.LastProcess(data);
  213. }
  214. catch (Exception ex)
  215. {
  216. data.Message = ex.Message;
  217. }
  218. data.TimeConsumption = Math.Round((DateTime.Now - start).TotalMilliseconds);
  219. });
  220. Parallel.ForEach(agvDataOnlineList, delegate (ResultAgvData agvData, ParallelLoopState loopState)
  221. {
  222. try
  223. {
  224. PlcStopAgv(agvData);
  225. }
  226. catch (Exception)
  227. {
  228. }
  229. });
  230. }
  231. private void PlcStopAgv(ResultAgvData agvData)
  232. {
  233. //查找AGV所在的正在进入和正在离开的所有工位
  234. var stations = StationDictionary.Values.Where(d =>
  235. {
  236. if (d.AgvList == null || d.AgvList.Count == 0) return false;
  237. return d.AgvList.Exists(s => s.carrier == agvData.AgvID && (s.agvPositionStatus == EPackAgvPositionStatus.Entering || s.agvPositionStatus == EPackAgvPositionStatus.Leaving));
  238. }).ToList();
  239. if (stations.Count == 0)
  240. {
  241. return;
  242. }
  243. string msg = null;
  244. //从AGV所在的工位中,获取需要停车的工位
  245. var stopStation = stations.FirstOrDefault(d =>
  246. {
  247. if (d.AgvList.Exists(s => s.carrier == agvData.AgvID && s.agvPositionStatus == EPackAgvPositionStatus.Entering))
  248. {
  249. var result = d.Interaction.StopAgvEntering(d, out string tempMsg);
  250. msg += $"{d.Config.LocationCode} {tempMsg}; ";
  251. if (result)
  252. {
  253. return true;
  254. }
  255. }
  256. if (d.AgvList.Exists(s => s.carrier == agvData.AgvID && s.agvPositionStatus == EPackAgvPositionStatus.Leaving))
  257. {
  258. var result = d.Interaction.StopAgvLeaving(d, out string tempMsg);
  259. msg += $"{d.Config.LocationCode} {tempMsg}; ";
  260. if (result)
  261. {
  262. return true;
  263. }
  264. }
  265. return false;
  266. });
  267. bool needPauseAgv = stopStation != null;
  268. bool agvPaused = agvData.AlarmList?.Exists(d => d.alarmId == 36) ?? false;
  269. if (needPauseAgv)
  270. {
  271. if (!agvPaused)
  272. {
  273. bool result = Crms.PmsApi.CarrierPause(agvData.AgvID);
  274. CLog.Instance.TaskLog.WriteInfo($"{stopStation?.Id} {agvData.AgvID}# 暂停小车{result.ToChineseString()} ({msg})");
  275. }
  276. }
  277. else
  278. {
  279. if (agvPaused)
  280. {
  281. bool result = Crms.PmsApi.CarrierResume(agvData.AgvID);
  282. CLog.Instance.TaskLog.WriteInfo($"{stations.FirstOrDefault()?.Id} {agvData.AgvID}# 恢复小车{result.ToChineseString()} ({msg})");
  283. }
  284. }
  285. }
  286. private void UserThread()
  287. {
  288. CLog.Instance.SystemLog.WriteDebug($"PackControlCrms已启动");
  289. while (true)
  290. {
  291. DateTime loopStartTime = DateTime.Now;
  292. try
  293. {
  294. //错开刷新
  295. var mod = counter % 20;
  296. if (mod >= 0 && mod <= forceWrite.Length)
  297. {
  298. for (int i = 0; i < forceWrite.Length; i++)
  299. {
  300. forceWrite[i] = mod == i;
  301. }
  302. }
  303. //DateTime start = DateTime.Now;
  304. UpdateStationDict();
  305. //System.Diagnostics.Trace.WriteLine($"UpdateStationDict {string.Join(" ", forces.Select(d => { return d ? "1" : "0"; }))} 耗时:{(DateTime.Now - start).TotalMilliseconds:F1} ms");
  306. }
  307. catch (Exception ex)
  308. {
  309. CLog.Instance.SystemLog.WriteException("PackControlCrms", ex);
  310. Thread.Sleep(5000);
  311. }
  312. firstStart = false;
  313. counter++;
  314. TimeConsumption = (DateTime.Now - loopStartTime).TotalMilliseconds;
  315. Thread.Sleep(500);
  316. }
  317. }
  318. }
  319. public class PackStationV2
  320. {
  321. public string Id { get; set; }
  322. public RouteConfig Config { get; set; }
  323. public IPackInteractionCrms Interaction { get; set; }
  324. public DateTime LastTaskAddTime { get; set; }
  325. public DateTime LastPreTaskAddTime { get; set; }
  326. public bool TaskAddCooled { get { return Math.Abs((DateTime.Now - LastTaskAddTime).TotalSeconds) > 5; } }
  327. public bool PreTaskAddCooled { get { return Math.Abs((DateTime.Now - LastPreTaskAddTime).TotalSeconds) > 5; } }
  328. public List<PackCarrier> LastAgvList { get; set; }
  329. public List<PackCarrier> AgvList { get; set; }
  330. public PackCarrier AgvApproachingData { get; set; }
  331. public PackCarrier AgvRequestEnterData { get; set; }
  332. public PackCarrier AgvEnteringData { get; set; }
  333. public PackCarrier AgvAtStationData { get; set; }
  334. public PackCarrier AgvLeavingData { get; set; }
  335. public PackCarrier AgvLeaveDoneData { get; set; }
  336. public int AgvIdApproaching { get; set; }
  337. public int AgvIdRequestEnter { get; set; }
  338. public int AgvIdEntering { get; set; }
  339. public int AgvIdAtStation { get; set; }
  340. public int AgvIdLeaving { get; set; }
  341. public int AgvIdLeaveDone { get; set; }
  342. public bool AgvApproaching { get; set; }
  343. public bool AgvRequestEnter { get; set; }
  344. public bool AgvEntering { get; set; }
  345. public bool AgvAtStation { get; set; }
  346. public bool AgvLeaving { get; set; }
  347. public bool AgvLeaveDone { get; set; }
  348. public bool AgvInArea { get { return AgvEntering || AgvAtStation || AgvLeaving; } }
  349. public bool AgvAtStationRise { get; set; }
  350. public bool AgvAtStationFall { get; set; }
  351. public int AgvAtStationAgvId { get; set; }
  352. public int AgvAtStationAlarmId { get; set; }
  353. public bool AgvAtStationAlarm { get; set; }
  354. public string AgvAtStationMaterial { get; set; }
  355. public string Message { get; set; }
  356. public string MessageWaitRequest { get; set; }
  357. public string MessageWaitStation { get; set; }
  358. public string MessageWaitLeave { get; set; }
  359. public double TimeConsumption { get; set; }
  360. }
  361. public interface IPackInteractionCrms
  362. {
  363. void Heartbeat(PackStationV2 data, bool agvHeartbeat);
  364. void CustomProcess(PackStationV2 data, bool firstStart, bool[] forceWrite);
  365. void LastProcess(PackStationV2 data);
  366. string GetNextLocation(PackStationV2 data, out string templateName, out string msg);
  367. bool StopAgvEntering(PackStationV2 data, out string msg);
  368. bool StopAgvLeaving(PackStationV2 data, out string msg);
  369. void AgvPositionStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List<TaskData> taskList);
  370. void AgvStationStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List<TaskData> taskList);
  371. void WaitTask(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  372. void WaitEnter(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  373. void AtRequest(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  374. void WaitRequest(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  375. void Entering(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  376. void AtStation(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  377. void WaitStation(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  378. void Leaving(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  379. void AtLeave(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  380. void WaitLeave(PackStationV2 data, PackCarrier agv, List<TaskData> taskList);
  381. void HandleAgvToPlc<T>(PackStationV2 data, PackCarrier agv, string plcAddrDesc, T agvValue);
  382. }
  383. public class PackInteractionCrmsBase : IPackInteractionCrms
  384. {
  385. protected int successCode = 20000;
  386. protected int unnecessaryCode = -20000;
  387. protected int failedCode = -1;
  388. protected bool ReadValue<T>(RouteConfig config, string plcAddrDesc, T plcValue, out T readValue, out string msg)
  389. {
  390. readValue = default(T);
  391. if (string.IsNullOrEmpty(config.PlcIpAddr))
  392. {
  393. msg = $"没有配置IP地址(PLC)";
  394. return false;
  395. }
  396. var plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc);
  397. if (string.IsNullOrEmpty(plcAddr))
  398. {
  399. msg = $"没有配置地址:{plcAddrDesc}";
  400. return false;
  401. }
  402. if (!config.PlcConnected)
  403. {
  404. msg = $"PLC未连接";
  405. return false;
  406. }
  407. var result = config.PlcReadWrite.ReadValue(plcAddr, plcValue, out var read);
  408. if (!read.IsSuccess)
  409. {
  410. msg = $"读取{plcAddrDesc} {plcAddr}失败 Code:{read.ErrorCode} Message:{read.Message}";
  411. return false;
  412. }
  413. msg = $"读取{plcAddrDesc} {plcAddr} = {read.Content}";
  414. readValue = read.Content;
  415. return result;
  416. }
  417. protected int ReadPlcValue(RouteConfig config, string plcAddrDesc, out string msg)
  418. {
  419. if (string.IsNullOrEmpty(config.PlcIpAddr))
  420. {
  421. msg = $"没有配置IP地址(PLC)";
  422. return unnecessaryCode;
  423. }
  424. var plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc);
  425. if (string.IsNullOrEmpty(plcAddr))
  426. {
  427. msg = $"没有配置地址:{plcAddrDesc}";
  428. return unnecessaryCode;
  429. }
  430. if (!config.PlcConnected)
  431. {
  432. msg = $"PLC未连接";
  433. return failedCode;
  434. }
  435. var read = config.PlcReadWrite.ReadBool(plcAddr);
  436. if (!read.IsSuccess)
  437. {
  438. msg = $"读取{plcAddrDesc} {plcAddr}失败 Code:{read.ErrorCode} Message:{read.Message}";
  439. return failedCode;
  440. }
  441. msg = $"读取{plcAddrDesc} {plcAddr} = {read.Content}";
  442. return read.Content ? successCode : 0;
  443. }
  444. protected string GetAgvDataString(ResultAgvData agvData)
  445. {
  446. return agvData == null ? null : $"({agvData.AgvID}# 路段:{agvData.GraphEdge} 导航点:{agvData.GraphVertex})";
  447. }
  448. protected string GetAllowStatusString(int allowStatus)
  449. {
  450. return allowStatus == 1 ? "通行" : "管制";
  451. }
  452. public virtual void Heartbeat(PackStationV2 data, bool agvHeartbeat)
  453. {
  454. //心跳信号处理
  455. var config = data.Config;
  456. if (config.PlcConnected
  457. && config.PlcReadWrite != null
  458. && !string.IsNullOrEmpty(config.PlcHeartbearAddr_AGV))
  459. {
  460. var tempResult2 = config.PlcReadWrite.Write(config.PlcHeartbearAddr_AGV, agvHeartbeat);
  461. if (!tempResult2.IsSuccess)
  462. {
  463. CLog.Instance.SystemLog.WriteInfo($"{config.LocationCode} {config.PlcIpAddr} 写入AGV心跳:{tempResult2.IsSuccess.ToChineseString()} {config.PlcHeartbearAddr_AGV} Code:{tempResult2.ErrorCode} Message:{tempResult2.Message}");
  464. }
  465. }
  466. }
  467. public virtual void CustomProcess(PackStationV2 data, bool firstStart, bool[] forceWrite)
  468. {
  469. //先处理到位AGV相关信息
  470. var agvId = data.AgvAtStationData == null ? 0 : data.AgvAtStationData.carrier;
  471. if (data.AgvAtStationAgvId != agvId || firstStart || forceWrite[8])
  472. {
  473. data.AgvAtStationAgvId = agvId;
  474. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV编号", (short)data.AgvAtStationAgvId);
  475. }
  476. var alarmId = data.AgvAtStationData?.AgvData?.AlarmList == null || data.AgvAtStationData.AgvData.AlarmList.Count == 0 ?
  477. 0 : data.AgvAtStationData.AgvData.AlarmList.OrderByDescending(d => d.alarmLevel).FirstOrDefault().alarmId;
  478. if (data.AgvAtStationAlarmId != alarmId || firstStart || forceWrite[9])
  479. {
  480. data.AgvAtStationAlarmId = alarmId;
  481. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV报警代码", (short)data.AgvAtStationAlarmId);
  482. }
  483. var agvAlarm = alarmId > 0;
  484. if (data.AgvAtStationAlarm != agvAlarm || firstStart || forceWrite[10])
  485. {
  486. data.AgvAtStationAlarm = agvAlarm;
  487. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV报警", data.AgvAtStationAlarm);
  488. }
  489. if (!string.IsNullOrWhiteSpace(data.Id.GetLocationMember("AGV物料")))
  490. {
  491. string agvMaterial = string.Empty;
  492. if (agvId > 0)
  493. {
  494. var res = Crms.PmsTaskService.GetAgvMaterial(new AgvMaterialDto { AgvId = agvId });
  495. var agvMaterialDto = res?.data as AgvMaterialDto;
  496. agvMaterial = agvMaterialDto?.MaterialBarcode ?? string.Empty;
  497. }
  498. if (data.AgvAtStationMaterial != agvMaterial || firstStart || forceWrite[11])
  499. {
  500. data.AgvAtStationMaterial = agvMaterial;
  501. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV物料", data.AgvAtStationMaterial);
  502. }
  503. }
  504. //工位相关信号
  505. var result = data.AgvApproachingData != null;
  506. if (data.AgvApproaching != result || firstStart || forceWrite[0])
  507. {
  508. data.AgvApproaching = result;
  509. data.Interaction.HandleAgvToPlc(data, data.AgvApproachingData, "AGV正在接近", data.AgvApproaching);
  510. }
  511. result = data.AgvRequestEnterData != null;
  512. if (data.AgvRequestEnter != result || firstStart || forceWrite[1])
  513. {
  514. data.AgvRequestEnter = result;
  515. data.Interaction.HandleAgvToPlc(data, data.AgvRequestEnterData, "AGV请求进入", data.AgvRequestEnter);
  516. }
  517. result = data.AgvEnteringData != null;
  518. if (data.AgvEntering != result || firstStart || forceWrite[2])
  519. {
  520. data.AgvEntering = result;
  521. data.Interaction.HandleAgvToPlc(data, data.AgvEnteringData, "AGV正在进入", data.AgvEntering);
  522. }
  523. result = data.AgvAtStationData != null;
  524. if (data.AgvAtStation != result || firstStart || forceWrite[3])
  525. {
  526. data.AgvAtStation = result;
  527. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV到位", data.AgvAtStation);
  528. }
  529. result = data.AgvLeavingData != null;
  530. if (data.AgvLeaving != result || firstStart || forceWrite[4])
  531. {
  532. data.AgvLeaving = result;
  533. data.Interaction.HandleAgvToPlc(data, data.AgvLeavingData, "AGV正在离开", data.AgvLeaving);
  534. }
  535. result = data.AgvLeaveDoneData != null;
  536. if (data.AgvLeaveDone != result || firstStart || forceWrite[5])
  537. {
  538. data.AgvLeaveDone = result;
  539. data.Interaction.HandleAgvToPlc(data, data.AgvLeaveDoneData, "AGV离开完成", data.AgvLeaveDone);
  540. }
  541. //LogicBit 9 上升到位状态 512
  542. //LogicBit 10 下降到位状态 1024
  543. result = data.AgvAtStationData?.AgvData != null ? data.AgvAtStationData.AgvData.LogicBits.GetBitVaule(9) : false;
  544. if (data.AgvAtStationRise != result || firstStart || forceWrite[6])
  545. {
  546. data.AgvAtStationRise = result;
  547. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV上升到位", data.AgvAtStationRise);
  548. }
  549. result = data.AgvAtStationData?.AgvData != null ? data.AgvAtStationData.AgvData.LogicBits.GetBitVaule(10) : false;
  550. if (data.AgvAtStationFall != result || firstStart || forceWrite[7])
  551. {
  552. data.AgvAtStationFall = result;
  553. data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV下降到位", data.AgvAtStationFall);
  554. }
  555. }
  556. public virtual void LastProcess(PackStationV2 data)
  557. {
  558. //消息清理
  559. if (data.AgvIdAtStation == 0)
  560. {
  561. data.Message = null;
  562. }
  563. if (data.AgvIdApproaching == 0 && data.AgvIdRequestEnter == 0)
  564. {
  565. data.MessageWaitRequest = null;
  566. }
  567. if (data.AgvIdEntering == 0 && data.AgvIdAtStation == 0)
  568. {
  569. data.MessageWaitStation = null;
  570. }
  571. if (data.AgvIdLeaving == 0 && data.AgvIdLeaveDone == 0)
  572. {
  573. data.MessageWaitLeave = null;
  574. }
  575. }
  576. public virtual string GetNextLocation(PackStationV2 data, out string templateName, out string msg)
  577. {
  578. var config = data.Config;
  579. templateName = null;
  580. var result = ReadPlcValue(config, "PLC放行", out msg);
  581. if (result <= 0)
  582. {
  583. return null;
  584. }
  585. string nextLocation = config.LocationCode.GetLocationMember("下个工位");
  586. if (string.IsNullOrWhiteSpace(nextLocation))
  587. {
  588. msg = $"{msg} 没配置下个工位";
  589. return null;
  590. }
  591. nextLocation = nextLocation.ToValueArray<string>()[0];
  592. //有放行信号
  593. var result2 = ReadPlcValue(config, "PLC返修", out var msg2);
  594. msg = $"{msg} {msg2}";
  595. if (result2 == unnecessaryCode || result2 == 0)
  596. {
  597. templateName = config.LocationCode.GetLocationMember("后任务模板");
  598. return nextLocation;
  599. }
  600. if (result2 < 0)
  601. {
  602. return null;
  603. }
  604. string ngLocation = config.LocationCode.GetLocationMember("返修工位");
  605. if (string.IsNullOrWhiteSpace(ngLocation))
  606. {
  607. msg = $"{msg} 没配置返修工位";
  608. return null;
  609. }
  610. templateName = config.LocationCode.GetLocationMember("返修任务模板");
  611. return ngLocation.ToValueArray<string>()[0];
  612. }
  613. public virtual bool StopAgvEntering(PackStationV2 data, out string msg)
  614. {
  615. var result = ReadPlcValue(data.Config, "PLC急停", out msg);
  616. if (result == failedCode || result == 0)
  617. {
  618. return true;
  619. }
  620. result = ReadPlcValue(data.Config, "PLC进入互锁", out msg);
  621. if (result == failedCode || result == 0)
  622. {
  623. return true;
  624. }
  625. return false;
  626. }
  627. public virtual bool StopAgvLeaving(PackStationV2 data, out string msg)
  628. {
  629. var result = ReadPlcValue(data.Config, "PLC急停", out msg);
  630. if (result == failedCode || result == 0)
  631. {
  632. return true;
  633. }
  634. result = ReadPlcValue(data.Config, "PLC离开互锁", out msg);
  635. if (result == failedCode || result == 0)
  636. {
  637. return true;
  638. }
  639. return false;
  640. }
  641. public virtual void AgvPositionStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List<TaskData> taskList)
  642. {
  643. var config = data.Config;
  644. CLog.Instance.TaskLog.WriteDebug($"{config.LocationCode} 位置状态 {lastAgv?.agvPositionStatus} -> {agv?.agvPositionStatus} {GetAgvDataString(agv?.AgvData)}");
  645. }
  646. public virtual void AgvStationStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List<TaskData> taskList)
  647. {
  648. var config = data.Config;
  649. CLog.Instance.TaskLog.WriteDebug($"{config.LocationCode} 工位状态 {lastAgv?.agvStationStatus} -> {agv?.agvStationStatus} {GetAgvDataString(agv?.AgvData)}");
  650. }
  651. public virtual void WaitTask(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  652. {
  653. if (!data.PreTaskAddCooled) return;
  654. if (agv.AgvData?.Status != 0) return;
  655. if (taskList.FirstOrDefault(d => d.Carrier == agv.carrier || d.BindingAGVNumber == agv.carrier) != null) return;
  656. var config = data.Config;
  657. CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} 添加前置任务 {GetAgvDataString(agv.AgvData)}");
  658. PmsTaskInfoDto dto = new PmsTaskInfoDto();
  659. dto.LocationCode = data.Id;
  660. dto.TargetLocationCode = data.Id;
  661. dto.Carrier = agv.carrier;
  662. dto.CarrierType = "0";
  663. dto.TemplateName = config.LocationCode.GetLocationMember("前任务模板");
  664. Crms.PmsTaskService.TaskAddNoCheck(dto, new string[] { });
  665. data.LastPreTaskAddTime = DateTime.Now;
  666. }
  667. public virtual void WaitEnter(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  668. {
  669. }
  670. public virtual void AtRequest(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  671. {
  672. }
  673. public virtual void WaitRequest(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  674. {
  675. if (agv.enter == 1) return;
  676. var config = data.Config;
  677. var result = ReadPlcValue(config, "PLC允许进入", out var msg);
  678. var allowStatus = result > 0 ? 1 : 0;
  679. msg = $"{msg} {GetAgvDataString(agv.AgvData)}";
  680. if (agv.enter != allowStatus)
  681. {
  682. var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, allowStatus, 0, 0);
  683. msg = $"{msg} 请求点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}";
  684. }
  685. if (data.MessageWaitRequest != msg)
  686. {
  687. CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}");
  688. }
  689. data.MessageWaitRequest = msg;
  690. }
  691. public virtual void Entering(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  692. {
  693. }
  694. public virtual void AtStation(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  695. {
  696. if (!data.TaskAddCooled) return;
  697. if (taskList.FirstOrDefault(d => d.TaskType != ETaskType.Charge && (d.Carrier == agv.carrier || d.BindingAGVNumber == agv.carrier)) != null) return;
  698. var nextLocation = GetNextLocation(data, out var templateName, out var msg);
  699. if (data.Message != msg)
  700. {
  701. CLog.Instance.TaskLog.WriteInfo($"{data.Id} {msg} {GetAgvDataString(agv.AgvData)}");
  702. }
  703. data.Message = msg;
  704. if (string.IsNullOrWhiteSpace(nextLocation))
  705. {
  706. return;
  707. }
  708. PmsTaskInfoDto dto = new PmsTaskInfoDto();
  709. dto.LocationCode = data.Id;
  710. dto.TargetLocationCode = nextLocation;
  711. dto.Carrier = agv.carrier;
  712. dto.CarrierType = "0";
  713. dto.TemplateName = templateName;
  714. Crms.PmsTaskService.TaskAddNoCheck(dto, new string[] { });
  715. data.LastTaskAddTime = DateTime.Now;
  716. data.Message = null;
  717. }
  718. public virtual void WaitStation(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  719. {
  720. if (agv.leaver == 1) return;
  721. var config = data.Config;
  722. var result = ReadPlcValue(config, "PLC放行", out var msg);
  723. var allowStatus = result > 0 ? 1 : 0;
  724. msg = $"{msg} {GetAgvDataString(agv.AgvData)}";
  725. if (agv.leaver != allowStatus)
  726. {
  727. var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, 0, allowStatus, 0);
  728. msg = $"{msg} 工位点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}";
  729. }
  730. if (data.MessageWaitStation != msg)
  731. {
  732. CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}");
  733. }
  734. data.MessageWaitStation = msg;
  735. }
  736. public virtual void Leaving(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  737. {
  738. }
  739. public virtual void AtLeave(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  740. {
  741. }
  742. public virtual void WaitLeave(PackStationV2 data, PackCarrier agv, List<TaskData> taskList)
  743. {
  744. if (agv.release == 1) return;
  745. var config = data.Config;
  746. var result = ReadPlcValue(config, "PLC离开完成", out var msg);
  747. var allowStatus = result > 0 ? 1 : 0;
  748. msg = $"{msg} {GetAgvDataString(agv.AgvData)}";
  749. if (agv.release != allowStatus)
  750. {
  751. var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, 0, 0, allowStatus);
  752. msg = $"{msg} 释放点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}";
  753. }
  754. if (data.MessageWaitLeave != msg)
  755. {
  756. CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}");
  757. }
  758. data.MessageWaitLeave = msg;
  759. }
  760. public virtual void HandleAgvToPlc<T>(PackStationV2 data, PackCarrier agv, string plcAddrDesc, T agvValue)
  761. {
  762. var config = data.Config;
  763. if (!config.PlcConnected || config.PlcReadWrite == null) return;
  764. string plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc);
  765. if (string.IsNullOrWhiteSpace(plcAddr)) return;
  766. var readResult = config.PlcReadWrite.ReadValue(plcAddr, agvValue, out var _);
  767. if (readResult) return;
  768. var result = config.PlcReadWrite.WriteValue(plcAddr, agvValue);
  769. var agvInfo = GetAgvDataString(agv?.AgvData);
  770. CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {plcAddrDesc} {plcAddr} = {agvValue} 写入{result.IsSuccess.ToChineseString()} {agvInfo}");
  771. }
  772. }
  773. }