ModbusTCP.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Event;
  3. using Aitex.Core.RT.IOCore;
  4. using Aitex.Core.RT.Log;
  5. using Aitex.Core.RT.OperationCenter;
  6. using Aitex.Core.RT.SCCore;
  7. using Aitex.Core.Util;
  8. using HslCommunication;
  9. using HslCommunication.ModBus;
  10. using MECF.Framework.Common.IOCore;
  11. using MECF.Framework.Common.PLC;
  12. using MECF.Framework.RT.Core.IoProviders;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Diagnostics;
  16. using System.Linq;
  17. using System.Text;
  18. using System.Threading.Tasks;
  19. using System.Xml;
  20. namespace FurnaceRT.Equipments.Systems
  21. {
  22. public class ModbusTCP : IoProvider
  23. {
  24. private string _address;
  25. private Int32 _port;
  26. private byte _station;
  27. public int _diStartAddress;
  28. public int _doStartAddress;
  29. public int _aiStartAddress;
  30. public int _aoStartAddress;
  31. public string _dataformat;
  32. public bool _addressstartwithzero;
  33. public bool _stringReverse;
  34. private ModbusTcpNet _readerClient = null;
  35. private WcfPlc _wcfPlc = null;
  36. public bool IsCommunicationError { get; set; } = false;
  37. private R_TRIG _trigRetryConnect = new R_TRIG();
  38. private Stopwatch _stopwatchTotal = new Stopwatch();
  39. private bool _enableLog = true;
  40. private int _failCount = 0;
  41. protected override void SetParameter(XmlElement nodeParameter)
  42. {
  43. _address = nodeParameter.GetAttribute("ip");
  44. _port = Convert.ToInt32(nodeParameter.GetAttribute("port"));
  45. _station = (byte)Convert.ToInt32(nodeParameter.GetAttribute("station_id"));
  46. //_stringReverse = Convert.ToBoolean(nodeParameter.GetAttribute("stringReverse"));
  47. _diStartAddress = int.Parse(nodeParameter.GetAttribute("diStartAddress"));
  48. _aiStartAddress = int.Parse(nodeParameter.GetAttribute("aiStartAddress"));
  49. _doStartAddress = int.Parse(nodeParameter.GetAttribute("doStartAddress"));
  50. _aoStartAddress = int.Parse(nodeParameter.GetAttribute("aoStartAddress"));
  51. //_dataformat = nodeParameter.GetAttribute("dataformat");
  52. //DisconnectAlarm = SubscribeAlarm($"{Name}.DisconnectAlarm", "", ResetAlarm);
  53. //DisconnectAlarm.Id = 1030;
  54. //CommunicationErrorAlarm = SubscribeAlarm($"{Name}.DisconnectAlarm", "", ResetAlarm);
  55. //CommunicationErrorAlarm.Id = 1031;
  56. _enableLog = SC.GetValue<bool>($"System.ModbusCommunicationEnableLogMessage");
  57. OP.Subscribe($"Sysytem.{Name}.ModbusPLC", InvokeReset);
  58. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  59. {
  60. _wcfPlc = new WcfPlc("System", "Heater", "WcfPlc_Heater");
  61. _wcfPlc.Initialize();
  62. }
  63. else
  64. {
  65. _readerClient = new ModbusTcpNet(_address, _port, _station);
  66. Open();
  67. }
  68. }
  69. public int _connecteTimes { get; set; }
  70. private R_TRIG _trigConnected = new R_TRIG();
  71. private R_TRIG _trigReadDoAndAo = new R_TRIG();
  72. //public override bool ResetAlarm()
  73. //{
  74. // Reset();
  75. // return true;
  76. //}
  77. public override void Initialize(string module, string name, List<IoBlockItem> lstBuffers, IIoBuffer buffer, XmlElement nodeParameter, string ioMappingPathFile, string ioModule)
  78. {
  79. //if (SC.GetValue<bool>("System.IsSimulatorMode"))
  80. // _wcfPlc.Initialize();
  81. base.Initialize(module, name, lstBuffers, buffer, nodeParameter, ioMappingPathFile, ioModule);
  82. }
  83. protected override bool OnTimer()
  84. {
  85. try
  86. {
  87. _stopwatchTotal.Start();
  88. foreach (var bufferSection in _blockSections)
  89. {
  90. if (bufferSection.Type == IoType.DI)
  91. {
  92. bool[] diBuffer = ReadDi(bufferSection.Offset, bufferSection.Size);
  93. if (diBuffer != null)
  94. {
  95. _buffer.SetDiBuffer(_source, bufferSection.Offset, diBuffer);
  96. //TraceArray(diBuffer);
  97. }
  98. }
  99. else if (bufferSection.Type == IoType.DO)
  100. {
  101. if (_trigConnected.Q && !_trigReadDoAndAo.M)
  102. {
  103. bool[] doBuffer = ReadDo(bufferSection.Offset, bufferSection.Size);
  104. if (doBuffer != null)
  105. {
  106. _buffer.SetDoBuffer(_source, bufferSection.Offset, doBuffer);
  107. }
  108. }
  109. }
  110. else if (bufferSection.Type == IoType.AI)
  111. {
  112. float[] aiBuffer = ReadAiFloat(bufferSection.Offset, bufferSection.Size);
  113. if (aiBuffer != null)
  114. {
  115. _buffer.SetAiBufferFloat(_source, bufferSection.Offset, aiBuffer);
  116. }
  117. }
  118. else if (bufferSection.Type == IoType.AO)
  119. {
  120. if (_trigConnected.Q && !_trigReadDoAndAo.M)
  121. {
  122. float[] aoBuffer = ReadAo(bufferSection.Offset, bufferSection.Size);
  123. if (aoBuffer != null)
  124. {
  125. _buffer.SetAoBufferFloat(_source, bufferSection.Offset, aoBuffer);
  126. }
  127. }
  128. }
  129. }
  130. if (!_trigReadDoAndAo.M)
  131. _trigReadDoAndAo.CLK = true;
  132. //if (SC.GetValue<bool>("System.IsSimulatorMode"))
  133. {
  134. Dictionary<int, bool[]> dos = _buffer.GetDoBuffer(_source);
  135. if (dos != null)
  136. {
  137. foreach (var doo in dos)
  138. {
  139. WriteDo(doo.Key, doo.Value);
  140. }
  141. }
  142. Dictionary<int, float[]> aos = _buffer.GetAoBufferFloat(_source);
  143. if (aos != null)
  144. {
  145. foreach (var ao in aos)
  146. {
  147. WriteAoFloat(ao.Key, ao.Value);
  148. }
  149. }
  150. }
  151. var comunicationSpanTotal = (int)_stopwatchTotal.ElapsedMilliseconds;
  152. //LOG.Write($"Modbus {comunicationSpanTotal}");
  153. _stopwatchTotal.Restart();
  154. }
  155. catch (Exception ex)
  156. {
  157. LOG.Write(ex);
  158. Close();
  159. }
  160. return true;
  161. }
  162. public override void Reset()
  163. {
  164. _trigError.RST = true;
  165. _trigNotConnected.RST = true;
  166. if (!_trigConnected.M)
  167. {
  168. if (!SC.GetValue<bool>("System.IsSimulatorMode"))
  169. {
  170. Close();
  171. Open();
  172. }
  173. }
  174. }
  175. private void TrigDisconnectAlarm()
  176. {
  177. _trigNotConnected.CLK = true;
  178. if (_trigNotConnected.T)
  179. {
  180. EV.PostInfoLog(Module, $"{Module} {_address}:{_port} connected");
  181. }
  182. if (_trigNotConnected.R)
  183. {
  184. EV.PostAlarmLog(Module, $"{Module} {_address}:{_port} not connected");
  185. }
  186. }
  187. protected override bool[] ReadDi(int offset, int size)
  188. {
  189. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  190. {
  191. int address = offset + _aiStartAddress;
  192. var ret = _wcfPlc.ReadBool(address.ToString(), out bool[] data, size, out _);
  193. return data;
  194. }
  195. else
  196. {
  197. if (_trigNotConnected.M)
  198. return null;
  199. var dataDi = DATA.Poll($"System.Heater.DIItemList");
  200. bool[] data = new bool[size];
  201. if (dataDi != null)
  202. {
  203. List<NotifiableIoItem> item = (List<NotifiableIoItem>)dataDi;
  204. int address = _diStartAddress;
  205. int iOldAddress = _diStartAddress;
  206. ushort iCount = 0;
  207. int iIndex = 0;
  208. for (int i = 0; i < item.Count; i++)
  209. {
  210. int.TryParse(item[i].Address, out int iNewAddress);
  211. if (iNewAddress == iOldAddress)
  212. {
  213. iCount++;
  214. continue;
  215. }
  216. else
  217. {
  218. if (iNewAddress == iOldAddress + 1)
  219. {
  220. iCount++;
  221. iOldAddress = iNewAddress;
  222. }
  223. else
  224. {
  225. var ret = _readerClient.ReadInt16(address.ToString(), iCount);
  226. if (ret.IsSuccess)
  227. {
  228. for (int j = 0; j < ret.Content.Length; j++)
  229. {
  230. data[iIndex + j] = ret.Content[j] > 0 ? true : false;
  231. }
  232. _failCount = 0;
  233. }
  234. else
  235. {
  236. _failCount++;
  237. }
  238. iIndex = iNewAddress - _diStartAddress;
  239. address = iNewAddress;
  240. iOldAddress = iNewAddress;
  241. iCount = 1;
  242. }
  243. }
  244. if (i == item.Count - 1)
  245. {
  246. var ret = _readerClient.ReadInt16(address.ToString(), iCount);
  247. if (ret.IsSuccess)
  248. {
  249. for (int j = 0; j < ret.Content.Length; j++)
  250. {
  251. data[iIndex + j] = ret.Content[j] > 0 ? true : false;
  252. }
  253. _failCount = 0;
  254. }
  255. else
  256. {
  257. _failCount++;
  258. }
  259. }
  260. }
  261. }
  262. if (_failCount >= 5)
  263. TrigDisconnectAlarm();
  264. return data;
  265. }
  266. }
  267. protected override float[] ReadAiFloat(int offset, int size)
  268. {
  269. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  270. {
  271. int address = offset + _aiStartAddress;
  272. var ret = _wcfPlc.ReadFloat(address.ToString(), out float[] data, size, out _);
  273. return data;
  274. }
  275. else
  276. {
  277. if (_trigNotConnected.M)
  278. return null;
  279. var dataAi = DATA.Poll($"System.Heater.AIItemList");
  280. float[] data = new float[size];
  281. if (dataAi != null)
  282. {
  283. List<NotifiableIoItem> item = (List<NotifiableIoItem>)dataAi;
  284. int address = _aiStartAddress;
  285. int iOldAddress = _aiStartAddress;
  286. ushort iCount = 0;
  287. int iIndex = 0;
  288. for (int i = 0; i < item.Count; i++)
  289. {
  290. int.TryParse(item[i].Address, out int iNewAddress);
  291. if (iNewAddress == iOldAddress)
  292. {
  293. iCount++;
  294. continue;
  295. }
  296. else
  297. {
  298. if (iNewAddress == iOldAddress + 2)
  299. {
  300. iCount++;
  301. iOldAddress = iNewAddress;
  302. }
  303. else
  304. {
  305. var ret = _readerClient.ReadFloatAsync(address.ToString(), iCount);
  306. if (ret.Result.IsSuccess)
  307. {
  308. for (int j = 0; j < ret.Result.Content.Length; j++)
  309. {
  310. data[iIndex + j * 2] = ret.Result.Content[j];
  311. }
  312. }
  313. iIndex = iNewAddress - _aiStartAddress;
  314. address = iNewAddress;
  315. iOldAddress = iNewAddress;
  316. iCount = 1;
  317. }
  318. }
  319. if (i == item.Count - 1)
  320. {
  321. var ret = _readerClient.ReadFloatAsync(address.ToString(), iCount);
  322. if (ret.Result.IsSuccess)
  323. {
  324. for (int j = 0; j < ret.Result.Content.Length; j++)
  325. {
  326. data[iIndex + j * 2] = ret.Result.Content[j];
  327. }
  328. }
  329. }
  330. }
  331. }
  332. return data;
  333. }
  334. }
  335. protected bool[] ReadDo(int offset, int size)
  336. {
  337. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  338. {
  339. return null;
  340. }
  341. else
  342. {
  343. var dataDo = DATA.Poll($"System.Heater.DOItemList");
  344. bool[] data = new bool[size];
  345. if (dataDo != null)
  346. {
  347. List<NotifiableIoItem> item = (List<NotifiableIoItem>)dataDo;
  348. int address = _doStartAddress;
  349. int iOldAddress = _doStartAddress;
  350. ushort iCount = 0;
  351. int iIndex = 0;
  352. for (int i = 0; i < item.Count; i++)
  353. {
  354. int.TryParse(item[i].Address, out int iNewAddress);
  355. if (iNewAddress == iOldAddress)
  356. {
  357. iCount++;
  358. continue;
  359. }
  360. else
  361. {
  362. if (iNewAddress == iOldAddress + 1)
  363. {
  364. iCount++;
  365. iOldAddress = iNewAddress;
  366. }
  367. else
  368. {
  369. var ret = _readerClient.ReadInt16(address.ToString(), iCount);
  370. if (ret.IsSuccess)
  371. {
  372. for (int j = 0; j < ret.Content.Length; j++)
  373. {
  374. data[iIndex + j] = ret.Content[j] > 0 ? true : false;
  375. }
  376. }
  377. iIndex = iNewAddress - _doStartAddress;
  378. address = iNewAddress;
  379. iOldAddress = iNewAddress;
  380. iCount = 1;
  381. }
  382. }
  383. if (i == item.Count - 1)
  384. {
  385. var ret = _readerClient.ReadInt16(address.ToString(), iCount);
  386. if (ret.IsSuccess)
  387. {
  388. for (int j = 0; j < ret.Content.Length; j++)
  389. {
  390. data[iIndex + j] = ret.Content[j] > 0 ? true : false;
  391. }
  392. }
  393. }
  394. }
  395. }
  396. return data;
  397. }
  398. }
  399. protected override short[] ReadAi(int offset, int size)
  400. {
  401. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  402. {
  403. int address = offset + _aiStartAddress;
  404. var ret = _wcfPlc.ReadInt16(address.ToString(), out short[] data, size, out _);
  405. return data;
  406. }
  407. else
  408. {
  409. int address = offset + _aiStartAddress;
  410. var ret = _readerClient.ReadInt16(address.ToString(), (ushort)size);
  411. if (!ret.IsSuccess) return null;
  412. return ret.Content;
  413. }
  414. }
  415. protected float[] ReadAo(int offset, int size)
  416. {
  417. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  418. {
  419. return null;
  420. }
  421. else
  422. {
  423. var dataAo = DATA.Poll($"System.Heater.AOItemList");
  424. float[] data = new float[size];
  425. if (dataAo != null)
  426. {
  427. List<NotifiableIoItem> item = (List<NotifiableIoItem>)dataAo;
  428. int address = _aoStartAddress;
  429. int iOldAddress = _aoStartAddress;
  430. ushort iCount = 0;
  431. int iIndex = 0;
  432. for (int i = 0; i < item.Count; i++)
  433. {
  434. int.TryParse(item[i].Address, out int iNewAddress);
  435. if (iNewAddress == iOldAddress)
  436. {
  437. iCount++;
  438. continue;
  439. }
  440. else
  441. {
  442. if (iNewAddress == iOldAddress + 2)
  443. {
  444. iCount++;
  445. iOldAddress = iNewAddress;
  446. }
  447. else
  448. {
  449. var ret = _readerClient.ReadFloat(address.ToString(), iCount);
  450. if (ret.IsSuccess)
  451. {
  452. for (int j = 0; j < ret.Content.Length; j++)
  453. {
  454. data[iIndex + j * 2] = ret.Content[j];
  455. }
  456. }
  457. iIndex = iNewAddress - _aoStartAddress;
  458. address = iNewAddress;
  459. iOldAddress = iNewAddress;
  460. iCount = 1;
  461. }
  462. }
  463. if (i == item.Count - 1)
  464. {
  465. var ret = _readerClient.ReadFloat(address.ToString(), iCount);
  466. if (ret.IsSuccess)
  467. {
  468. for (int j = 0; j < ret.Content.Length; j++)
  469. {
  470. data[iIndex + j * 2] = ret.Content[j];
  471. }
  472. }
  473. }
  474. }
  475. }
  476. return data;
  477. }
  478. }
  479. public override bool SetValueFloat(AOAccessor aoItem, float value)
  480. {
  481. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  482. return true;
  483. if (!_trigConnected.M)
  484. return false;
  485. if (_trigNotConnected.M)
  486. return false;
  487. try
  488. {
  489. int address = aoItem.Index + _aoStartAddress;
  490. var ret = _readerClient.Write(address.ToString(), new float[] { value });
  491. return ret.IsSuccess;
  492. }
  493. catch (Exception)
  494. {
  495. _trigConnected.CLK = false;
  496. return false;
  497. }
  498. }
  499. public override bool SetValue(DOAccessor doItem, bool value)
  500. {
  501. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  502. return true;
  503. if (!_trigConnected.M)
  504. return false;
  505. if (_trigNotConnected.M)
  506. return false;
  507. try
  508. {
  509. int address = doItem.Index + _doStartAddress;
  510. var ret2 = _readerClient.Write(address.ToString(), (short)(value ? 1 : 0));
  511. return ret2.IsSuccess;
  512. }
  513. catch (Exception)
  514. {
  515. _trigConnected.CLK = false;
  516. return false;
  517. }
  518. }
  519. protected override void Close()
  520. {
  521. try
  522. {
  523. _readerClient.ConnectClose();
  524. _readerClient.Dispose();
  525. _trigConnected.RST = true;
  526. }
  527. catch (Exception ex)
  528. {
  529. LOG.Write(ex.Message);
  530. }
  531. }
  532. protected override void Open()
  533. {
  534. _readerClient.IpAddress = _address;
  535. _readerClient.Port = _port;
  536. _readerClient?.ConnectClose();
  537. try
  538. {
  539. var ret = _readerClient.ConnectServer();
  540. if (ret.IsSuccess)
  541. _trigConnected.CLK = true;
  542. else
  543. {
  544. //DisconnectAlarm.Description = ret.Message;
  545. //DisconnectAlarm.Set();
  546. LOG.Write(ret.Message);
  547. }
  548. }
  549. catch (Exception ex)
  550. {
  551. IsCommunicationError = true;
  552. LOG.Write(ex.Message);
  553. //CommunicationErrorAlarm.Description = ex.Message;
  554. //CommunicationErrorAlarm.Set();
  555. }
  556. }
  557. public byte[] ReadResultRender<T>(OperateResult<T> result, string address)
  558. {
  559. byte[] buffer = new byte[32];
  560. if (result.IsSuccess)
  561. {
  562. _connecteTimes = 0;
  563. IsCommunicationError = false;
  564. var dat2 = (Convert.ToUInt32(result.Content.ToString()) & 0xFFFF);
  565. var dat1 = (Convert.ToUInt32(result.Content.ToString()) >> 16 & 0xFFFF);
  566. uint[] data = new uint[] { dat1, dat2 };
  567. for (int j = 0; j < 2; j++)
  568. {
  569. for (int i = 0; i < 16; i++)
  570. {
  571. buffer[j * 16 + i] = Convert.ToByte((data[j] >> i) & 0x01);
  572. }
  573. }
  574. string str = string.Join("", Array.ConvertAll(buffer, x => x.ToString()));
  575. if (_enableLog)
  576. LOG.Info($"Read Success,Data:{ str} ({ result.Content.ToString()}:{dat1}、{dat2})");
  577. return buffer;
  578. }
  579. else
  580. {
  581. IsCommunicationError = true;
  582. EV.PostAlarmLog("System.PLC", $"[{address}] Read Failed {Environment.NewLine}Reason:{result.ToMessageShowString()}");
  583. }
  584. return buffer;
  585. }
  586. public void WriteResultRender(OperateResult result, string address, int data, string str)
  587. {
  588. if (result.IsSuccess)
  589. {
  590. _connecteTimes = 0;
  591. IsCommunicationError = false;
  592. if (_enableLog)
  593. LOG.Info("Write Success,Data" + str + "(" + data.ToString() + ")");
  594. }
  595. else
  596. {
  597. IsCommunicationError = true;
  598. EV.PostAlarmLog("System.PLC", $"[{address}] Write Failed {Environment.NewLine}Reason:{result.ToMessageShowString()}");
  599. }
  600. }
  601. public bool InvokeReset(string arg1, object[] arg2)
  602. {
  603. _connecteTimes = 0;
  604. IsCommunicationError = false;
  605. _trigRetryConnect.RST = true;
  606. return true;
  607. }
  608. protected override void WriteDo(int offset, bool[] buffer)
  609. {
  610. if (_readerClient != null)
  611. {
  612. return;
  613. int address = offset + _doStartAddress;
  614. List<short> temp = new List<short>();
  615. for(int i=0;i<buffer.Length;i++)
  616. {
  617. temp.Add((short)(buffer[i] ? 1 : 0));
  618. }
  619. var ret = _readerClient.Write(address.ToString(), temp.ToArray());
  620. }
  621. else
  622. {
  623. int address = offset + _doStartAddress;
  624. _wcfPlc.WriteBool(address.ToString(), buffer, out string reason);
  625. }
  626. }
  627. protected override void WriteAo(int offset, short[] buffer)
  628. {
  629. }
  630. protected override void WriteAoFloat(int offset, float[] data)
  631. {
  632. if(_readerClient != null)
  633. {
  634. return;
  635. int address = offset + _aoStartAddress;
  636. int size = 2;
  637. float[] temp;
  638. int i = 0;
  639. for (; i < data.Length / size; i++)
  640. {
  641. temp = new float[size];
  642. Array.Copy(data, i * size, temp, 0, size);
  643. var ret = _readerClient.Write((address + i* size).ToString(), temp);
  644. if (!ret.IsSuccess)
  645. {
  646. return;
  647. }
  648. }
  649. if (data.Length - i * size > 0)
  650. {
  651. temp = new float[data.Length - i * size];
  652. Array.Copy(data, i * size, temp, 0, data.Length - i * size);
  653. var ret = _readerClient.Write((address + i * size).ToString(), temp);
  654. if (!ret.IsSuccess)
  655. {
  656. return;
  657. }
  658. }
  659. }
  660. else
  661. {
  662. int address = offset + _aoStartAddress;
  663. _wcfPlc?.WriteFloat(address.ToString(), data, out _);
  664. }
  665. }
  666. }
  667. }