ConnectionBase.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO.Ports;
  4. using System.Net.Sockets;
  5. using System.Threading;
  6. using Aitex.Core.RT.Event;
  7. using Aitex.Core.RT.Log;
  8. using Aitex.Core.Util;
  9. namespace MECF.Framework.Common.Communications
  10. {
  11. public abstract class SerialPortConnectionBase : IConnection
  12. {
  13. public string Address
  14. {
  15. get { return _address; }
  16. }
  17. public bool IsConnected
  18. {
  19. get { return _port.IsOpen(); }
  20. }
  21. public bool Connect()
  22. {
  23. return _port.Open();
  24. }
  25. public bool Disconnect()
  26. {
  27. _port.Close();
  28. return true;
  29. }
  30. public void TerminateCom()
  31. {
  32. _port.Dispose();
  33. }
  34. public bool IsBusy
  35. {
  36. get { return _activeHandler != null; }
  37. }
  38. public HandlerBase ActiveHandler => _activeHandler;
  39. public bool IsCommunicationError { get; private set; }
  40. public string LastCommunicationError { get; private set; }
  41. private AsyncSerialPort _port;
  42. protected HandlerBase _activeHandler; //set, control,
  43. private object _lockerActiveHandler = new object();
  44. private string _address;
  45. private bool _isAsciiMode;
  46. public int retryTime = 0;
  47. public int MaxTryTime = 5;
  48. private PeriodicJob _thread;
  49. private object _locker = new object();
  50. private LinkedList<string> _lstAsciiMsgs = new LinkedList<string>();
  51. private LinkedList<byte[]> _lstBinsMsgs = new LinkedList<byte[]>();
  52. private string _newLine;
  53. public SerialPortConnectionBase(string port, int baudRate = 9600, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One, string newline = "\r", bool isAsciiMode = true)
  54. {
  55. _address = port;
  56. _isAsciiMode = isAsciiMode;
  57. _newLine = newline;
  58. _port = new AsyncSerialPort(port, baudRate, dataBits, parity, stopBits, newline, isAsciiMode);
  59. _port.OnDataChanged += _port_OnAsciiDataReceived;
  60. _port.OnBinaryDataChanged += _port_OnBinaryDataChanged;
  61. _port.OnErrorHappened += _port_OnErrorHappened;
  62. _thread = new PeriodicJob(2, OnTimer, $"{port}.MonitorHandler", true);
  63. }
  64. private bool OnTimer()
  65. {
  66. lock (_locker)
  67. {
  68. if (_isAsciiMode)
  69. {
  70. while (_lstAsciiMsgs.Count > 0)
  71. {
  72. string asciiMsg = _lstAsciiMsgs.First.Value;
  73. _port_HandleAsciiData(asciiMsg);
  74. _lstAsciiMsgs.RemoveFirst();
  75. }
  76. }
  77. else
  78. {
  79. while (_lstBinsMsgs.Count > 0)
  80. {
  81. byte[] binMsg = _lstBinsMsgs.First.Value;
  82. _port_HandleBinarayData(binMsg);
  83. _lstBinsMsgs.RemoveFirst();
  84. }
  85. }
  86. }
  87. return true;
  88. }
  89. public void SetPortAddress(string portName)
  90. {
  91. _port.PortName = portName;
  92. }
  93. private void _port_OnErrorHappened(string obj)
  94. {
  95. LOG.Error(obj);
  96. }
  97. public virtual bool SendMessage(string message)
  98. {
  99. if (_port != null && _port.IsOpen())
  100. return _port.Write(message);
  101. LOG.Error($"No connection writing message {message}");
  102. return false;
  103. }
  104. public virtual bool SendMessage(byte[] message)
  105. {
  106. if (_port != null && _port.IsOpen())
  107. return _port.Write(message);
  108. LOG.Error($"No connection writing message {string.Join(" ", Array.ConvertAll(message, x => x.ToString("X2")))}");
  109. return false;
  110. }
  111. public void ForceClear()
  112. {
  113. lock (_lockerActiveHandler)
  114. {
  115. IsCommunicationError = false;
  116. _activeHandler = null;
  117. }
  118. }
  119. public void Execute(HandlerBase handler)
  120. {
  121. if (_activeHandler != null)
  122. return;
  123. if (handler == null)
  124. return;
  125. if (_port.IsOpen())
  126. {
  127. lock (_lockerActiveHandler)
  128. {
  129. retryTime = 0;
  130. _activeHandler = handler;
  131. _activeHandler.SetState(EnumHandlerState.Sent);
  132. }
  133. bool sendResult = _isAsciiMode ? SendMessage(handler.SendText) : SendMessage(handler.SendBinary);
  134. if (!sendResult)
  135. {
  136. lock (_lockerActiveHandler)
  137. {
  138. _activeHandler = null;
  139. }
  140. }
  141. }
  142. }
  143. protected virtual MessageBase ParseResponse(string rawMessage)
  144. {
  145. return null;
  146. }
  147. protected virtual MessageBase ParseResponse(byte[] rawMessage)
  148. {
  149. return null;
  150. }
  151. protected virtual void OnEventArrived(MessageBase msg)
  152. {
  153. }
  154. protected virtual void ActiveHandlerProceedMessage(MessageBase msg)
  155. {
  156. lock (_lockerActiveHandler)
  157. {
  158. if (_activeHandler != null)
  159. {
  160. if (msg.IsFormatError || (_activeHandler.HandleMessage(msg, out bool transactionComplete) && transactionComplete))
  161. {
  162. _activeHandler = null;
  163. }
  164. }
  165. }
  166. }
  167. public void EnableLog(bool enable)
  168. {
  169. _port.EnableLog = enable;
  170. }
  171. private void ProceedTransactionMessage(MessageBase msg)
  172. {
  173. if (msg == null || msg.IsFormatError)
  174. {
  175. SetCommunicationError(true, "received invalid response message.");
  176. return;
  177. }
  178. if (msg.IsEvent)
  179. {
  180. OnEventArrived(msg);
  181. //return;
  182. }
  183. //当前活动交互会话,继续执行
  184. ActiveHandlerProceedMessage(msg);
  185. }
  186. private void _port_OnBinaryDataChanged(byte[] binaryData)
  187. {
  188. lock (_locker)
  189. {
  190. _lstBinsMsgs.AddLast(binaryData);
  191. }
  192. }
  193. private void _port_HandleBinarayData(byte[] binaryData)
  194. {
  195. MessageBase msg = ParseResponse(binaryData);
  196. ProceedTransactionMessage(msg);
  197. }
  198. private void _port_OnAsciiDataReceived(string oneLineMessage)
  199. {
  200. lock (_locker)
  201. {
  202. if (string.IsNullOrEmpty(_newLine))
  203. {
  204. _lstAsciiMsgs.AddLast(oneLineMessage);
  205. if (_port.EnableLog)
  206. LOG.Info(string.Format("Communication {0} Receive {1}.", _port.PortName, oneLineMessage));
  207. }
  208. else
  209. {
  210. foreach (var message in oneLineMessage.Split(_newLine.ToCharArray()))
  211. {
  212. if (!string.IsNullOrEmpty(message))
  213. {
  214. _lstAsciiMsgs.AddLast(message + _newLine);
  215. if (_port.EnableLog)
  216. LOG.Info(string.Format("Communication {0} Receive {1}.", _port.PortName, message + _newLine));
  217. }
  218. }
  219. }
  220. }
  221. }
  222. private void _port_HandleAsciiData(string oneLineMessage)
  223. {
  224. MessageBase msg = ParseResponse(oneLineMessage);
  225. ProceedTransactionMessage(msg);
  226. }
  227. public HandlerBase MonitorTimeout()
  228. {
  229. HandlerBase result = null;
  230. lock (_lockerActiveHandler)
  231. {
  232. if (_activeHandler != null && _activeHandler.CheckTimeout())
  233. {
  234. if (retryTime < MaxTryTime)
  235. {
  236. retryTime += 1;
  237. Retry();
  238. return result;
  239. }
  240. string strSubfix = retryTime > 0 ? $"after retry {retryTime}" : string.Empty;
  241. EV.PostWarningLog("System", $"{Address} receive {_activeHandler.Name} timeout {strSubfix}");
  242. result = _activeHandler;
  243. _activeHandler = null;
  244. SetCommunicationError(true, "receive response timeout");
  245. //}
  246. }
  247. }
  248. return result;
  249. }
  250. public void Retry()
  251. {
  252. if (_activeHandler == null)
  253. return;
  254. if (_port.IsOpen())
  255. {
  256. //_activeHandler = handler;
  257. _activeHandler.SetState(EnumHandlerState.Sent);
  258. bool sendResult = _isAsciiMode ? SendMessage(_activeHandler.SendText) : SendMessage(_activeHandler.SendBinary);
  259. if (_isAsciiMode)
  260. {
  261. if (_port.EnableLog)
  262. LOG.Info(string.Format("Communication {0} Send {1} succeeded.", _port.PortName, _activeHandler.SendText));
  263. }
  264. else
  265. {
  266. if (_port.EnableLog)
  267. LOG.Info(string.Format("Communication {0} Send {1} succeeded.", _port.PortName, string.Join(" ", Array.ConvertAll(_activeHandler.SendBinary, x => x.ToString("X2")))));
  268. }
  269. if (!sendResult) _activeHandler = null;
  270. }
  271. }
  272. public void SetCommunicationError(bool isError, string reason)
  273. {
  274. IsCommunicationError = isError;
  275. LastCommunicationError = reason;
  276. }
  277. }
  278. public abstract class TCPPortConnectionBase : IConnection
  279. {
  280. public string Address
  281. {
  282. get { return _address; }
  283. }
  284. public bool IsConnected
  285. {
  286. get { return _socket.IsConnected; }
  287. }
  288. public bool Connect()
  289. {
  290. _socket.Connect();
  291. int iCount = 0;
  292. while (!IsConnected && iCount < 25)
  293. {
  294. Thread.Sleep(200);
  295. iCount++;
  296. }
  297. if (IsConnected)
  298. {
  299. return true;
  300. }
  301. else
  302. {
  303. Disconnect();
  304. return false;
  305. }
  306. }
  307. public bool Disconnect()
  308. {
  309. _socket.Dispose();
  310. return true;
  311. }
  312. public bool IsBusy
  313. {
  314. get { return _activeHandler != null; }
  315. }
  316. public HandlerBase ActiveHandler => _activeHandler;
  317. public bool IsCommunicationError { get; private set; }
  318. public string LastCommunicationError { get; private set; }
  319. private AsynSocketClient _socket;
  320. protected HandlerBase _activeHandler; //set, control,
  321. public HandlerBase HandlerInError;
  322. protected object _lockerActiveHandler = new object();
  323. private string _address;
  324. private bool _isAsciiMode;
  325. public int retryTime = 0;
  326. public int MaxTryTime = 1;
  327. private PeriodicJob _thread;
  328. private object _locker = new object();
  329. private LinkedList<string> _lstAsciiMsgs = new LinkedList<string>();
  330. private LinkedList<byte[]> _lstBinsMsgs = new LinkedList<byte[]>();
  331. private string _newLine;
  332. public TCPPortConnectionBase(string address, string newline = "\r", bool isAsciiMode = true, ProtocolType protocolType= ProtocolType.Tcp)
  333. {
  334. _address = address;
  335. _newLine = newline;
  336. _isAsciiMode = isAsciiMode;
  337. _socket = new AsynSocketClient(address, isAsciiMode, newline, protocolType);
  338. _socket.OnDataChanged += _port_OnAsciiDataReceived;
  339. _socket.OnBinaryDataChanged += _port_OnBinaryDataChanged;
  340. _socket.OnErrorHappened += _port_OnErrorHappened;
  341. _thread = new PeriodicJob(1, OnTimer, $"{address}.MonitorHandler", true);
  342. }
  343. private bool OnTimer()
  344. {
  345. lock (_locker)
  346. {
  347. if (_isAsciiMode)
  348. {
  349. while (_lstAsciiMsgs.Count > 0)
  350. {
  351. string asciiMsg = _lstAsciiMsgs.First.Value;
  352. if (!string.IsNullOrEmpty(asciiMsg))
  353. {
  354. if (_socket.NeedLog)
  355. {
  356. LOG.Write($"Start handler message:{asciiMsg}");
  357. }
  358. _port_HandleAsciiData(asciiMsg);
  359. }
  360. _lstAsciiMsgs.RemoveFirst();
  361. }
  362. }
  363. else
  364. {
  365. while (_lstBinsMsgs.Count > 0)
  366. {
  367. byte[] binMsg = _lstBinsMsgs.First.Value;
  368. _port_HandleBinarayData(binMsg);
  369. _lstBinsMsgs.RemoveFirst();
  370. }
  371. }
  372. }
  373. return true;
  374. }
  375. //public void SetPortAddress(string portName)
  376. //{
  377. // _port.PortName = portName;
  378. //}
  379. private void _port_OnErrorHappened(TCPErrorEventArgs obj)
  380. {
  381. LOG.Error(obj.Reason);
  382. }
  383. public virtual bool SendMessage(string message)
  384. {
  385. if (_socket != null && _socket.IsConnected)
  386. return _socket.Write(message);
  387. LOG.Error($"No connection writing message {message}");
  388. return false;
  389. }
  390. public virtual bool SendMessage(byte[] message)
  391. {
  392. if (_socket != null && _socket.IsConnected)
  393. return _socket.Write(message);
  394. LOG.Error($"No connection writing message {string.Join(" ", Array.ConvertAll(message, x => x.ToString("X2")))}");
  395. return false;
  396. }
  397. public void ForceClear()
  398. {
  399. lock (_lockerActiveHandler)
  400. {
  401. _activeHandler = null;
  402. IsCommunicationError = false;
  403. }
  404. }
  405. public void Execute(HandlerBase handler)
  406. {
  407. if (_activeHandler != null)
  408. return;
  409. if (handler == null)
  410. return;
  411. if (_socket.IsConnected)
  412. {
  413. lock (_lockerActiveHandler)
  414. {
  415. retryTime = 0;
  416. _activeHandler = handler;
  417. _activeHandler.SetState(EnumHandlerState.Sent);
  418. }
  419. bool sendResult = _isAsciiMode ? SendMessage(handler.SendText) : SendMessage(handler.SendBinary);
  420. if (!sendResult)
  421. {
  422. lock (_lockerActiveHandler)
  423. {
  424. _activeHandler = null;
  425. }
  426. }
  427. }
  428. }
  429. protected virtual MessageBase ParseResponse(string rawMessage)
  430. {
  431. return null;
  432. }
  433. protected virtual MessageBase ParseResponse(byte[] rawMessage)
  434. {
  435. return null;
  436. }
  437. protected virtual void OnEventArrived(MessageBase msg)
  438. {
  439. }
  440. protected virtual void ActiveHandlerProceedMessage(MessageBase msg)
  441. {
  442. lock (_lockerActiveHandler)
  443. {
  444. if (_activeHandler != null)
  445. {
  446. if (msg.IsFormatError || (_activeHandler.HandleMessage(msg, out bool transactionComplete) && transactionComplete))
  447. {
  448. _activeHandler = null;
  449. }
  450. }
  451. }
  452. }
  453. public void EnableLog(bool enable)
  454. {
  455. _socket.NeedLog = enable;
  456. }
  457. private void ProceedTransactionMessage(MessageBase msg)
  458. {
  459. if (msg == null || msg.IsFormatError)
  460. {
  461. SetCommunicationError(true, "received invalid response message.");
  462. return;
  463. }
  464. if (msg.IsEvent)
  465. {
  466. OnEventArrived(msg);
  467. //return;
  468. }
  469. //当前活动交互会话,继续执行
  470. ActiveHandlerProceedMessage(msg);
  471. }
  472. private void _port_OnBinaryDataChanged(byte[] binaryData)
  473. {
  474. lock (_locker)
  475. {
  476. _lstBinsMsgs.AddLast(binaryData);
  477. }
  478. }
  479. private void _port_HandleBinarayData(byte[] binaryData)
  480. {
  481. MessageBase msg = ParseResponse(binaryData);
  482. ProceedTransactionMessage(msg);
  483. }
  484. private void _port_OnAsciiDataReceived(string oneLineMessage)
  485. {
  486. lock (_locker)
  487. {
  488. if (string.IsNullOrEmpty(_newLine))
  489. {
  490. _lstAsciiMsgs.AddLast(oneLineMessage);
  491. }
  492. else
  493. {
  494. foreach (var message in oneLineMessage.Split(_newLine.ToCharArray()))
  495. {
  496. if (!string.IsNullOrEmpty(message))
  497. _lstAsciiMsgs.AddLast(message + _newLine);
  498. }
  499. }
  500. }
  501. //lock (_locker)
  502. //{
  503. // _lstAsciiMsgs.AddLast(oneLineMessage);
  504. //}
  505. }
  506. private void _port_HandleAsciiData(string oneLineMessage)
  507. {
  508. MessageBase msg = ParseResponse(oneLineMessage);
  509. ProceedTransactionMessage(msg);
  510. }
  511. public HandlerBase MonitorTimeout()
  512. {
  513. HandlerBase result = null;
  514. lock (_lockerActiveHandler)
  515. {
  516. if (_activeHandler != null && _activeHandler.CheckTimeout())
  517. {
  518. if (retryTime < MaxTryTime)
  519. {
  520. retryTime += 1;
  521. EV.PostWarningLog("System", $"{Address} receive {_activeHandler.Name} timeout in {retryTime} times");
  522. Retry();
  523. return result;
  524. }
  525. string strSubfix = retryTime > 0 ? $"after retry {retryTime}" : string.Empty;
  526. EV.PostWarningLog("System", $"{Address} receive {_activeHandler.Name} timeout {strSubfix}");
  527. result = _activeHandler;
  528. HandlerInError = _activeHandler;
  529. _activeHandler = null;
  530. SetCommunicationError(true, "receive response timeout");
  531. //}
  532. }
  533. }
  534. return result;
  535. }
  536. public void Retry()
  537. {
  538. if (_activeHandler == null)
  539. return;
  540. if (_socket.IsConnected)
  541. {
  542. //_activeHandler = handler;
  543. _activeHandler.SetState(EnumHandlerState.Sent);
  544. bool sendResult = _isAsciiMode ? SendMessage(_activeHandler.SendText) : SendMessage(_activeHandler.SendBinary);
  545. if (!sendResult) _activeHandler = null;
  546. }
  547. }
  548. public void SetCommunicationError(bool isError, string reason)
  549. {
  550. IsCommunicationError = isError;
  551. LastCommunicationError = reason;
  552. }
  553. }
  554. }