DeviceControl.cs 18 KB

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