DeviceControl.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. using DbCommon.BusinessCore.BaseCore;
  2. using DbCommon.Enties.DbModels;
  3. using ProjectManagementSystem.Common.Config;
  4. using ProjectManagementSystem.Common.Extenions;
  5. using ProjectManagementSystem.Common.Logger;
  6. using ProjectManagementSystem.Device.Command;
  7. using ProjectManagementSystem.Device.CommandCallback;
  8. using ProjectManagementSystem.Device.Core;
  9. using System;
  10. using System.Collections.Concurrent;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. namespace ProjectManagementSystem.Common.Core
  17. {
  18. public class DeviceControl
  19. {
  20. private static DeviceControl m_instance;
  21. private CommandRoller commandRollerQuery = new CommandRoller();
  22. public CasunCommunication Communication { get; private set; }
  23. public static DeviceControl Instance
  24. {
  25. get
  26. {
  27. if (m_instance == null)
  28. {
  29. m_instance = new DeviceControl();
  30. if (!m_instance.Initialize())
  31. {
  32. m_instance = null;
  33. }
  34. }
  35. return m_instance;
  36. }
  37. }
  38. private DeviceControl()
  39. {
  40. }
  41. private bool Initialize()
  42. {
  43. string ipAddress = Function.AppSetting.TryGetValue<string>("ListenIp");
  44. int port = Function.AppSetting.TryGetValue<int>("ListenPort");
  45. string comPortName = Function.AppSetting.TryGetValue<string>("ComPortName");
  46. Communication = new CasunCommunication();
  47. Communication.OnInfoRoller += Communication_OnInfoRoller;
  48. Communication.OnInfoIO += Communication_OnInfoIO;
  49. Communication.OnInfoBox += Communication_OnInfoBox;
  50. Communication.OnInfoBoxRelease += Communication_OnInfoBoxRelease;
  51. Communication.OnInfoAgv += Communication_OnInfoAgv;
  52. if (!string.IsNullOrEmpty(ipAddress))
  53. {
  54. var tcp = new CommunicationTcp(ipAddress, port);
  55. tcp.OnLogMsg += LogMsg;
  56. tcp.DataReceived += (addr, data) => Communication.Handling(addr, data);
  57. tcp.Start();
  58. if (tcp.IsStart) { Communication.Communications.Add(tcp); }
  59. else { return false; }
  60. var udp = new CommunicationUdp(ipAddress, port);
  61. udp.OnLogMsg += LogMsg;
  62. udp.DataReceived += (addr, data) => Communication.Handling(addr, data);
  63. udp.Start();
  64. if (udp.IsStart) { Communication.Communications.Add(udp); }
  65. else { return false; }
  66. }
  67. if (!string.IsNullOrEmpty(comPortName))
  68. {
  69. var com = new CommunicationCom(comPortName, 9600);
  70. com.OnLogMsg += LogMsg;
  71. com.DataReceived += (addr, data) => Communication.Handling(addr, data);
  72. com.Start();
  73. if (com.IsStart) { Communication.Communications.Add(com); }
  74. else { return false; }
  75. }
  76. var vcu = CommunicationVcu.Instance;
  77. vcu.OnLogMsg += LogMsg;
  78. vcu.DataReceived += (addr, data) => Communication.Handling(addr, data);
  79. Communication.Communications.Add(vcu);
  80. CLog.Instance.SystemLog.WriteDebug($"DeviceControl已启动");
  81. return true;
  82. }
  83. private void Communication_OnInfoAgv(InfoAgv info)
  84. {
  85. CLog.Instance.SystemLog.WriteDebug($"AGV{info.AgvId}:地标{info.Mark} 路线{info.Route} 状态{info.Status}({info.StatusText}),报警状态{info.Alarm}({info.AlarmText})");
  86. }
  87. private void Communication_OnInfoBoxRelease(InfoBoxRelease info)
  88. {
  89. if (info.BoxReleaseLightOn)
  90. {
  91. CLog.Instance.SystemLog.WriteInfo($"放行盒已亮灯,地标{info.Mark} 路线{info.Route} AGV{info.AgvId}");
  92. }
  93. if (info.BoxReleaseAgv)
  94. {
  95. CLog.Instance.SystemLog.WriteInfo($"放行盒已放行,地标{info.Mark} 路线{info.Route} AGV{info.AgvId}");
  96. }
  97. }
  98. private void Communication_OnInfoBox(InfoBox info)
  99. {
  100. if (info.BoxCalled || info.BoxCancelCall)
  101. {
  102. RouteCalled.Instance.Call(info.Route, info.BoxCalled, info.BoxCancelCall);
  103. return;
  104. }
  105. }
  106. private void Communication_OnInfoIO(InfoIO info)
  107. {
  108. //if (info.DataValid
  109. // && info.DeviceId > 0)
  110. //{
  111. // RouteConfig routeConfig = ExcelConfig.Instance.RouteConfigList.FirstOrDefault(d => d.IOTransID == info.DeviceId);
  112. // if (routeConfig != null)
  113. // {
  114. // RouteCalled.Instance.Call(routeConfig.Route, info.X1);
  115. // }
  116. //}
  117. }
  118. private void Communication_OnInfoRoller(InfoRoller info)
  119. {
  120. //if (info.DataValid
  121. // && info.DeviceId > 0)
  122. //{
  123. // RouteConfig routeConfig = ExcelConfig.Instance.RouteConfigList.FirstOrDefault(d => d.RollerID == info.DeviceId);
  124. // if (routeConfig != null)
  125. // {
  126. // if (info.FullTray)
  127. // {
  128. // RouteCalled.Instance.Call(routeConfig.Route, true);
  129. // }
  130. // else
  131. // {
  132. // if (routeConfig.CancelLineStauts == 0)
  133. // {
  134. // RouteCalled.Instance.Call(routeConfig.Route, false);
  135. // }
  136. // if (routeConfig.CancelLineStauts == 2)
  137. // {
  138. // if (info.FullEmpty)
  139. // {
  140. // RouteCalled.Instance.Call(routeConfig.Route, false);
  141. // }
  142. // else
  143. // {
  144. // RouteCalled.Instance.Call(routeConfig.Route, true);
  145. // }
  146. // }
  147. // }
  148. // }
  149. //}
  150. }
  151. private void LogMsg(string obj, Exception ex)
  152. {
  153. if (ex == null)
  154. {
  155. CLog.Instance.DeviceLog.WriteDebug(obj);
  156. }
  157. else
  158. {
  159. CLog.Instance.DeviceLog.WriteException("DeviceControl", obj, ex);
  160. }
  161. }
  162. #region IO透传功能
  163. private int GetIOAddressIndex(string address)
  164. {
  165. //解析地址,格式Y1-Y8(输出信号)
  166. var invalidValue = -1;
  167. if (string.IsNullOrEmpty(address)) return invalidValue;
  168. if (!int.TryParse(address.Substring(1), out int index))
  169. {
  170. return invalidValue;
  171. }
  172. index--;
  173. if (index < 0)
  174. {
  175. return invalidValue;
  176. }
  177. return index;
  178. }
  179. public bool CheckInputIO(int id, string[] addressArray, bool[] bitArray, out string msg)
  180. {
  181. msg = null;
  182. for (int i = 0; i < addressArray.Length; i++)
  183. {
  184. string plcAddr = addressArray[i];
  185. bool plcValue = bitArray[i];
  186. var result2 = GetInputIO(id, addressArray[i]);
  187. if (result2.Item1 == false
  188. || result2.Item2 != plcValue)
  189. {
  190. msg = $"等待信号({plcAddr}={plcValue})";
  191. return false;
  192. }
  193. }
  194. return true;
  195. }
  196. public bool CheckOutputIO(int id, string[] addressArray, bool[] bitArray, out string msg)
  197. {
  198. msg = null;
  199. for (int i = 0; i < addressArray.Length; i++)
  200. {
  201. string plcAddr = addressArray[i];
  202. bool plcValue = bitArray[i];
  203. var result = GetOutputIO(id, addressArray[i]);
  204. if (result.Item1 == false
  205. || result.Item2 != plcValue)
  206. {
  207. msg = $"写入失败({plcAddr}写入{plcValue})";
  208. return false;
  209. }
  210. }
  211. return true;
  212. }
  213. public Tuple<bool, bool> GetInputIO(int id, string address)
  214. {
  215. int index = GetIOAddressIndex(address);
  216. if (index < 0) return new Tuple<bool, bool>(false, false);
  217. if (!Communication.InfoIODictionary.ContainsKey(id))
  218. {
  219. return new Tuple<bool, bool>(false, false);
  220. }
  221. var info = Communication.InfoIODictionary[id];
  222. if (!info.DataValid) return new Tuple<bool, bool>(false, false);
  223. bool bitTrue = (info.Input & (0x01 << index)) > 0;
  224. return new Tuple<bool, bool>(true, bitTrue);
  225. }
  226. public Tuple<bool, bool> GetOutputIO(int id, string address)
  227. {
  228. int index = GetIOAddressIndex(address);
  229. if (index < 0) return new Tuple<bool, bool>(false, false);
  230. if (!Communication.InfoIODictionary.ContainsKey(id))
  231. {
  232. return new Tuple<bool, bool>(false, false);
  233. }
  234. var info = Communication.InfoIODictionary[id];
  235. if (!info.DataValid) return new Tuple<bool, bool>(false, false);
  236. bool bitTrue = (info.Output & (0x01 << index)) > 0;
  237. return new Tuple<bool, bool>(true, bitTrue);
  238. }
  239. public void SetOutputIO(int id, string address, bool bit)
  240. {
  241. SetOutputIO(id, new string[] { address }, new bool[] { bit });
  242. }
  243. public void SetOutputIO(int id, string[] addressArray, bool[] bitArray)
  244. {
  245. if (addressArray == null || addressArray.Length == 0) return;
  246. if (bitArray == null || bitArray.Length == 0) return;
  247. int[] indexArray = new int[addressArray.Length];
  248. for (int i = 0; i < addressArray.Length; i++)
  249. {
  250. string address = addressArray[i];
  251. indexArray[i] = GetIOAddressIndex(address);
  252. }
  253. SetOutputIO(id, indexArray, bitArray);
  254. }
  255. public bool SetOutputIO_ThenCheck(int id, string[] addressArray, bool[] bitArray, out string msg)
  256. {
  257. msg = null;
  258. SetOutputIO(id, addressArray, bitArray);
  259. for (int i = 0; i < 5; i++)
  260. {
  261. if (CheckOutputIO(id, addressArray, bitArray, out msg))
  262. {
  263. return true;
  264. }
  265. Thread.Sleep(20);
  266. }
  267. return false;
  268. }
  269. public void SetOutputIO(int id, int[] indexArray, bool[] bitArray)
  270. {
  271. if (!Communication.InfoIODictionary.ContainsKey(id))
  272. {
  273. return;
  274. }
  275. var info = Communication.InfoIODictionary[id];
  276. if (!info.DataValid) return;
  277. ushort newOutput = info.Output;
  278. for (int i = 0; i < indexArray.Length; i++)
  279. {
  280. int index = indexArray[i];
  281. if (index < 0)
  282. {
  283. return;
  284. }
  285. bool bit = bitArray[i];
  286. if (bit)
  287. {
  288. newOutput = (ushort)(newOutput | (0x01 << index));
  289. }
  290. else
  291. {
  292. newOutput = (ushort)(newOutput & (ushort.MaxValue - (1 << index)));
  293. }
  294. }
  295. SetOutputIO(id, newOutput);
  296. }
  297. public void SetOutputIO(int id, ushort output)
  298. {
  299. var data = new CommandIO();
  300. data.TargetID = (byte)id;
  301. data.Output = output;
  302. SendCommand(data, id, Communication.InfoIODictionary);
  303. }
  304. public void SetOutputIOClear(int id)
  305. {
  306. if (Communication.InfoIODictionary.ContainsKey(id)
  307. && Communication.InfoIODictionary[id].Output != 0)
  308. {
  309. SetOutputIO(id, 0);
  310. CLog.Instance.SystemLog.WriteInfo($"对接盒ID{id},清零输出");
  311. Thread.Sleep(100);
  312. }
  313. }
  314. #endregion
  315. #region 滚筒台对接
  316. public void RollerOperate(int id, ushort code)
  317. {
  318. var data = new CommandRoller();
  319. data.TargetID = (byte)id;
  320. data.ActionCode = code;
  321. SendCommand(data, id, Communication.InfoRollerDictionary);
  322. }
  323. public void RollerOperateClear(int id)
  324. {
  325. var data = new CommandRoller();
  326. data.TargetID = (byte)id;
  327. data.Operate = 0;
  328. data.ActionCode = 0;
  329. SendCommand(data, id, Communication.InfoRollerDictionary);
  330. }
  331. public void RollerActionClear(int id)
  332. {
  333. var data = new CommandRoller();
  334. data.TargetID = (byte)id;
  335. data.ActionCode = 0;
  336. SendCommand(data, id, Communication.InfoRollerDictionary);
  337. }
  338. public void RollerQuery(int id)
  339. {
  340. commandRollerQuery.Function = 0x21;
  341. commandRollerQuery.TargetID = (byte)id;
  342. SendCommand(commandRollerQuery, id, Communication.InfoRollerDictionary);
  343. }
  344. public void RollerQuery()
  345. {
  346. var configList = ExcelConfig.Instance.RouteConfigList;
  347. for (int i = 0; i < configList.Count; i++)
  348. {
  349. var config = configList[i];
  350. if (config.RollerID > 0)
  351. {
  352. RollerQuery(config.RollerID);
  353. }
  354. }
  355. }
  356. #endregion
  357. #region 报警灯功能
  358. public void SetAlarmLight(int id, int lightType)
  359. {
  360. var data = new CommandAlarmLight();
  361. data.DeviceId = (byte)id;
  362. data.LightType = (byte)lightType;
  363. SendCommand(data, id, Communication.InfoAlarmLightDictionary);
  364. }
  365. #endregion
  366. #region 叫料盒功能
  367. public void CallBoxQuery(int route)
  368. {
  369. var data = new CommandBox();
  370. data.Route = (byte)route;
  371. data.Function = 0x40;
  372. SendCommand(data, route, Communication.InfoBoxDictionary);
  373. }
  374. public void CallBoxLightOff(int route)
  375. {
  376. var data = new CommandBox();
  377. data.Route = (byte)route;
  378. data.Function = 0x45;
  379. SendCommand(data, route, Communication.InfoBoxDictionary);
  380. }
  381. #endregion
  382. #region 放行盒功能
  383. public void ReleaseBoxLightOn(int mark, int route = 0, int agvId = 0)
  384. {
  385. var data = new CommandBox();
  386. data.Mark = (byte)mark;
  387. data.Route = (byte)route;
  388. data.AgvId = (byte)agvId;
  389. data.Function = 0x35;
  390. SendCommand(data, agvId, Communication.InfoBoxDictionary);
  391. }
  392. public void ReleaseBoxLightOff(int mark, int route = 0, int agvId = 0)
  393. {
  394. var data = new CommandBox();
  395. data.Mark = (byte)mark;
  396. data.Route = (byte)route;
  397. data.AgvId = (byte)agvId;
  398. data.Function = 0x38;
  399. SendCommand(data, agvId, Communication.InfoBoxDictionary);
  400. }
  401. #endregion
  402. #region 有轨AGV
  403. public void ReleaseAgvOnStop(int mark, int route, int agvId)
  404. {
  405. var data = new CommandBox();
  406. data.Mark = (byte)mark;
  407. data.Route = (byte)route;
  408. data.AgvId = (byte)agvId;
  409. data.Function = 0x37;
  410. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  411. }
  412. public void ReleaseAgvOnStop(int mark, int route, int targetMark, int agvId)
  413. {
  414. var data = new CommandBoxRelease();
  415. data.Mark = (byte)mark;
  416. data.Spare = (byte)targetMark;
  417. data.Route = (byte)route;
  418. data.AgvId = (byte)agvId;
  419. data.Function = 0x37;
  420. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  421. }
  422. public void ReleaseAgvOnStandby(int mark, int route, int agvId)
  423. {
  424. var data = new CommandBox();
  425. data.Mark = (byte)mark;
  426. data.Route = (byte)route;
  427. data.AgvId = (byte)agvId;
  428. data.Function = 0x31;
  429. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  430. }
  431. public void RailAgv_Query1061(int agvId = 0)
  432. {
  433. var data = new Command1061();
  434. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  435. }
  436. public void RailAgv_Query1063(int fps, int agvId = 0)
  437. {
  438. var data = new Command1063();
  439. data.FPS = fps;
  440. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  441. }
  442. public void RailAgv_Query()
  443. {
  444. for (int i = 1; i <= 3; i++)
  445. {
  446. RailAgv_Query1063(i);
  447. Thread.Sleep(100);
  448. }
  449. }
  450. public void RailAgv_StartButton(int agvId)
  451. {
  452. RailAgv_Control1071(agvId, 0, 0);
  453. }
  454. public void RailAgv_StopButton(int agvId)
  455. {
  456. RailAgv_Control1071(agvId, 1, 0);
  457. }
  458. public void RailAgv_Control1071(int agvId, int iOperation = 0, int iSpeed = 0)
  459. {
  460. var data = new Command1071();
  461. data.Function = 0x71;
  462. data.Operation = (byte)iOperation;
  463. data.Speed = (byte)iSpeed;
  464. data.AgvId = (byte)agvId;
  465. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  466. }
  467. /// <summary>
  468. /// 改变AGV速度
  469. /// </summary>
  470. /// <param name="agvId">AGV编号</param>
  471. /// <param name="speed">AGV速度,单位:m/min</param>
  472. public void RailAgv_SpeedChange(int agvId, decimal speed)
  473. {
  474. var data = new CommandBox();
  475. data.Spare = (int)Math.Round(speed * 100);
  476. data.AgvId = (byte)agvId;
  477. data.Function = 0x47;
  478. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  479. }
  480. public void RailAgv_ReleaseAlarm(int agvId, int alarmSec)
  481. {
  482. var data = new CommandBox();
  483. data.Spare = (byte)alarmSec;
  484. data.AgvId = (byte)agvId;
  485. data.Function = 0x49;
  486. SendCommand(data, agvId, Communication.InfoAgvDictionary);
  487. }
  488. #endregion
  489. /// <summary>
  490. /// 根据设备ID查找设备终结点,并向指定终结点发送指令
  491. /// </summary>
  492. /// <typeparam name="TKey"></typeparam>
  493. /// <typeparam name="TValue"></typeparam>
  494. /// <param name="cmd"></param>
  495. /// <param name="deviceId"></param>
  496. /// <param name="infoDict"></param>
  497. public void SendCommand<TKey, TValue>(IDeviceCommand cmd, TKey deviceId, IDictionary<TKey, TValue> infoDict)
  498. where TKey : struct
  499. where TValue : BaseInfo
  500. {
  501. string ipAddress = null;
  502. if (infoDict.ContainsKey(deviceId))
  503. {
  504. ipAddress = infoDict[deviceId].RemoteEndPoint;
  505. }
  506. var data = cmd.Serialization();
  507. //CLog.Instance.SystemLog.WriteInfo($"Send {ipAddress} {data.ToHexString()}");
  508. Communication.SendCommand(data, ipAddress);
  509. }
  510. }
  511. }