FinsPlc.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Xml;
  7. using Aitex.Core.RT.DataCenter;
  8. using Aitex.Core.RT.Event;
  9. using Aitex.Core.RT.IOCore;
  10. using Aitex.Core.RT.Log;
  11. using Aitex.Core.RT.OperationCenter;
  12. using Aitex.Core.RT.SCCore;
  13. using Aitex.Core.Util;
  14. using MECF.Framework.Common.Communications;
  15. using MECF.Framework.Common.PLC;
  16. using MECF.Framework.RT.Core.IoProviders;
  17. using System.Net.Sockets;
  18. namespace MECF.Framework.Common.PLC
  19. {
  20. public enum BlockType
  21. {
  22. CIO = 0x30,
  23. WR = 0x31,
  24. D = 0x82,
  25. }
  26. public class FinsPlc : IoProvider, IConnection
  27. {
  28. public string Address
  29. {
  30. get { return $"{_ip}:{_port}"; }
  31. }
  32. public bool IsConnected
  33. {
  34. get { return IsOpened; }
  35. }
  36. public bool Connect()
  37. {
  38. return true;
  39. }
  40. public bool Disconnect()
  41. {
  42. return true;
  43. }
  44. TcpClient msender;
  45. Socket msock;
  46. byte[] Client, Server;
  47. private bool _isOpened = false;
  48. private bool _isDOLoaded = false;
  49. private string _ip = "192.168.10.10";
  50. private int _port = 9600;
  51. private int _aoBlockStartPosition = 1000;
  52. private int _aiBlockStartPosition = 2000;
  53. private int _doBlockStartPosition = 0;
  54. private int _diBlockStartPosition = 20;
  55. private BlockType _diBlockType = BlockType.WR;
  56. private BlockType _doBlockType = BlockType.WR;
  57. private BlockType _aiBlockType = BlockType.D;
  58. private BlockType _aoBlockType = BlockType.D;
  59. R_TRIG _failedTrigger = new R_TRIG();
  60. DeviceTimer _timerWrite = new DeviceTimer();
  61. DeviceTimer _timerRead = new DeviceTimer();
  62. private double _averageWriteTime = 0;
  63. private double _averageReadTime = 0;
  64. private int _sendTimeout = 0;
  65. private int _receiveTimeout = 0;
  66. private DeviceTimer _sendTime = new DeviceTimer();
  67. private DeviceTimer _receiveTime = new DeviceTimer();
  68. private int _sendTimeOkCount = 0;
  69. private double _lastSendTime = 0;
  70. private int _receiveTimeOkCount = 0;
  71. private double _lastReceiveTime = 0;
  72. public FinsPlc()
  73. {
  74. _sendTimeout = SC.GetValueOrDefault<int>("System.PLCSendTimeout");
  75. _receiveTimeout = SC.GetValueOrDefault<int>("System.PLCReceiveTimeout");
  76. }
  77. protected override void SetParameter(XmlElement nodeParameter)
  78. {
  79. string strIp = nodeParameter.GetAttribute("ip");
  80. string strPort = nodeParameter.GetAttribute("port");
  81. string diBlockType = nodeParameter.GetAttribute("diBlockType");
  82. string doBlockType = nodeParameter.GetAttribute("doBlockType");
  83. string aiBlockType = nodeParameter.GetAttribute("aiBlockType");
  84. string aoBlockType = nodeParameter.GetAttribute("aoBlockType");
  85. string diStartPosition = nodeParameter.GetAttribute("diStartPosition");
  86. string doStartPosition = nodeParameter.GetAttribute("doStartPosition");
  87. string aiStartPosition = nodeParameter.GetAttribute("aiStartPosition");
  88. string aoStartPosition = nodeParameter.GetAttribute("aoStartPosition");
  89. _port = int.Parse(strPort);
  90. _ip = strIp;
  91. if (!Enum.TryParse(diBlockType, out _diBlockType))
  92. {
  93. LOG.Error($"plc config error, block type {diBlockType} not valid");
  94. }
  95. if (!Enum.TryParse(doBlockType, out _doBlockType))
  96. {
  97. LOG.Error($"plc config error, block type {doBlockType} not valid");
  98. }
  99. if (!Enum.TryParse(aiBlockType, out _aiBlockType))
  100. {
  101. LOG.Error($"plc config error, block type {aiBlockType} not valid");
  102. }
  103. if (!Enum.TryParse(aoBlockType, out _aoBlockType))
  104. {
  105. LOG.Error($"plc config error, block type {aoBlockType} not valid");
  106. }
  107. if (!int.TryParse(diStartPosition, out _diBlockStartPosition))
  108. {
  109. LOG.Error($"plc config error, start position {diStartPosition} not valid");
  110. }
  111. if (!int.TryParse(doStartPosition, out _doBlockStartPosition))
  112. {
  113. LOG.Error($"plc config error, start position {doStartPosition} not valid");
  114. }
  115. if (!int.TryParse(aiStartPosition, out _aiBlockStartPosition))
  116. {
  117. LOG.Error($"plc config error, start position {aiStartPosition} not valid");
  118. }
  119. if (!int.TryParse(aoStartPosition, out _aoBlockStartPosition))
  120. {
  121. LOG.Error($"plc config error, start position {aoStartPosition} not valid");
  122. }
  123. }
  124. public override void Initialize(string module, string name, List<IoBlockItem> lstBuffers, IIoBuffer buffer, XmlElement nodeParameter, string ioMappingPathFile, string ioModule)
  125. {
  126. Module = module;
  127. Name = name;
  128. _source = module + "." + name;
  129. _buffer = buffer;
  130. _nodeParameter = nodeParameter;
  131. _blockSections = lstBuffers;
  132. buffer.SetBufferBlock(_source, lstBuffers);
  133. SetParameter(nodeParameter);
  134. buffer.SetIoMapByModule(_source, 0, ioMappingPathFile, ioModule);
  135. //SetIoMap(_source, 0, ioMappingPathFile, ioModule);
  136. State = IoProviderStateEnum.Uninitialized;
  137. _thread = new PeriodicJob(50, OnTimer, name);
  138. }
  139. private int GetIndex(string addr, int first)
  140. {
  141. if (String.IsNullOrEmpty(addr))
  142. {
  143. LOG.Write("GetIndex addr is empty");
  144. return -1;
  145. }
  146. string[] parts = addr.Trim().ToUpper().Split('.');
  147. int len = parts.Length;
  148. if (len == 1)
  149. {
  150. string ch = parts[0].TrimStart('D');
  151. int index = Convert.ToUInt16(ch);
  152. return (index - first);
  153. }
  154. if (len == 2)
  155. {
  156. char[] trim = { 'W', 'C', 'I', 'O', ' ' };
  157. string ch = parts[0].TrimStart(trim);
  158. int index = Convert.ToUInt16(ch);
  159. int bit = Convert.ToUInt16(parts[1]);
  160. return (index - first) * 16 + bit;
  161. }
  162. LOG.Info("IOManager GetIndex error");
  163. return -1;
  164. }
  165. //private void SetIoMap(string provider, int blockOffset, string xmlPathFile, string module = "")
  166. //{
  167. // XmlDocument xml = new XmlDocument();
  168. // xml.Load(xmlPathFile);
  169. // XmlNodeList lstDi = xml.SelectNodes("IO_DEFINE/Dig_In/DI_ITEM");
  170. // var scConfig = SC.GetConfigItem("System.IsIgnoreSaveDB");
  171. // var isIgnoreSaveDB = scConfig == null ? false : scConfig.BoolValue;
  172. // //<DI_ITEM Index="0" Name="" BufferOffset="0" Addr="0" Description=""/>
  173. // var dibuffer = _buffer.GetDiBuffer(provider);
  174. // List<DIAccessor> diList = new List<DIAccessor>();
  175. // foreach (var diItem in lstDi)
  176. // {
  177. // XmlElement element = diItem as XmlElement;
  178. // if (element == null)
  179. // continue;
  180. // string index = element.GetAttribute("Index");
  181. // string name = element.GetAttribute("Name");
  182. // string address = element.GetAttribute("Addr");
  183. // string description = element.GetAttribute("Description");
  184. // if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(index) || string.IsNullOrEmpty(address))
  185. // continue;
  186. // name = name.Trim();
  187. // index = index.Trim();
  188. // string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
  189. // int intIndex;
  190. // if (!int.TryParse(index, out intIndex))
  191. // continue;
  192. // int intBufferOffset = GetIndex(address, _diBlockStartPosition);
  193. // if (intBufferOffset == -1)
  194. // {
  195. // throw new Exception($"address not valid, " + provider);
  196. // }
  197. // if (!dibuffer.ContainsKey(blockOffset))
  198. // {
  199. // throw new Exception("Not defined DI buffer from IO provider, " + provider);
  200. // }
  201. // DIAccessor diAccessor = new DIAccessor(moduleName, intBufferOffset, dibuffer[blockOffset], dibuffer[blockOffset]);
  202. // diAccessor.IoTableIndex = intIndex;
  203. // diAccessor.Addr = address;
  204. // diAccessor.Provider = provider;
  205. // diAccessor.BlockOffset = blockOffset;
  206. // diAccessor.Description = description;
  207. // diList.Add(diAccessor);
  208. // }
  209. // _buffer.SetIoMap(provider, blockOffset, diList);
  210. // XmlNodeList lstDo = xml.SelectNodes("IO_DEFINE/Dig_Out/DO_ITEM");
  211. // var dobuffer = _buffer.GetDoBuffer(provider);
  212. // List<DOAccessor> doList = new List<DOAccessor>();
  213. // foreach (var doItem in lstDo)
  214. // {
  215. // XmlElement element = doItem as XmlElement;
  216. // if (element == null)
  217. // continue;
  218. // string index = element.GetAttribute("Index");
  219. // string name = element.GetAttribute("Name");
  220. // string address = element.GetAttribute("Addr");
  221. // string description = element.GetAttribute("Description");
  222. // if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(index) || string.IsNullOrEmpty(address))
  223. // continue;
  224. // name = name.Trim();
  225. // index = index.Trim();
  226. // string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
  227. // int intIndex;
  228. // if (!int.TryParse(index, out intIndex))
  229. // continue;
  230. // int intBufferOffset = GetIndex(address, _doBlockStartPosition);
  231. // if (intBufferOffset == -1)
  232. // {
  233. // throw new Exception($"address not valid, " + provider);
  234. // }
  235. // if (!dobuffer.ContainsKey(blockOffset))
  236. // {
  237. // throw new Exception("Not defined DO buffer from IO provider, " + provider);
  238. // }
  239. // DOAccessor doAccessor = new DOAccessor(moduleName, intBufferOffset, dobuffer[blockOffset]);
  240. // doAccessor.IoTableIndex = intIndex;
  241. // doAccessor.Addr = address;
  242. // doAccessor.Provider = provider;
  243. // doAccessor.BlockOffset = blockOffset;
  244. // doAccessor.Description = description;
  245. // doList.Add(doAccessor);
  246. // }
  247. // _buffer.SetIoMap(provider, blockOffset, doList);
  248. // XmlNodeList lstAo = xml.SelectNodes("IO_DEFINE/Ana_Out/AO_ITEM");
  249. // var aobuffer = _buffer.GetAoBuffer(provider);
  250. // List<AOAccessor> aoList = new List<AOAccessor>();
  251. // foreach (var aoItem in lstAo)
  252. // {
  253. // XmlElement element = aoItem as XmlElement;
  254. // if (element == null)
  255. // continue;
  256. // string index = element.GetAttribute("Index");
  257. // string name = element.GetAttribute("Name");
  258. // string address = element.GetAttribute("Addr");
  259. // string description = element.GetAttribute("Description");
  260. // if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(index) || string.IsNullOrEmpty(address))
  261. // continue;
  262. // name = name.Trim();
  263. // index = index.Trim();
  264. // string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
  265. // int intIndex;
  266. // if (!int.TryParse(index, out intIndex))
  267. // continue;
  268. // int intBufferOffset = GetIndex(address, _aoBlockStartPosition);
  269. // if (intBufferOffset == -1)
  270. // {
  271. // throw new Exception($"address not valid, " + provider);
  272. // }
  273. // if (!aobuffer.ContainsKey(blockOffset))
  274. // {
  275. // throw new Exception("Not defined AO buffer from IO provider, " + provider);
  276. // }
  277. // AOAccessor aoAccessor = new AOAccessor(moduleName, intBufferOffset, aobuffer[blockOffset]);
  278. // aoAccessor.IoTableIndex = intIndex;
  279. // aoAccessor.Addr = address;
  280. // aoAccessor.Provider = provider;
  281. // aoAccessor.BlockOffset = blockOffset;
  282. // aoAccessor.Description = description;
  283. // aoList.Add(aoAccessor);
  284. // }
  285. // _buffer.SetIoMap(provider, blockOffset, aoList);
  286. // XmlNodeList lstAi = xml.SelectNodes("IO_DEFINE/Ana_In/AI_ITEM");
  287. // var aibuffer = _buffer.GetAiBuffer(provider);
  288. // List<AIAccessor> aiList = new List<AIAccessor>();
  289. // foreach (var aiItem in lstAi)
  290. // {
  291. // XmlElement element = aiItem as XmlElement;
  292. // if (element == null)
  293. // continue;
  294. // string index = element.GetAttribute("Index");
  295. // string name = element.GetAttribute("Name");
  296. // string address = element.GetAttribute("Addr");
  297. // string description = element.GetAttribute("Description");
  298. // if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(index) || string.IsNullOrEmpty(address))
  299. // continue;
  300. // name = name.Trim();
  301. // index = index.Trim();
  302. // string moduleName = string.IsNullOrEmpty(module) ? name : $"{module}.{name}";
  303. // int intIndex;
  304. // if (!int.TryParse(index, out intIndex))
  305. // continue;
  306. // int intBufferOffset = GetIndex(address, _aiBlockStartPosition);
  307. // if (intBufferOffset == -1)
  308. // {
  309. // throw new Exception($"address not valid, " + provider);
  310. // }
  311. // if (!aibuffer.ContainsKey(blockOffset))
  312. // {
  313. // throw new Exception("Not defined AI buffer from IO provider, " + provider);
  314. // }
  315. // AIAccessor aiAccessor = new AIAccessor(moduleName, intBufferOffset, aibuffer[blockOffset]);
  316. // aiAccessor.IoTableIndex = intIndex;
  317. // aiAccessor.Addr = address;
  318. // aiAccessor.Provider = provider;
  319. // aiAccessor.BlockOffset = blockOffset;
  320. // aiAccessor.Description = description;
  321. // aiList.Add(aiAccessor);
  322. // }
  323. // _buffer.SetIoMap(provider, blockOffset, aiList);
  324. //}
  325. protected override void Open()
  326. {
  327. try
  328. {
  329. LOG.Write(String.Format("试图连接PLC {0}:{1}", _ip, _port));
  330. Close();
  331. _isOpened = false;
  332. msender = new TcpClient(_ip, _port);
  333. msender.SendTimeout = _sendTimeout;
  334. msender.ReceiveTimeout = _receiveTimeout;
  335. msock = msender.Client;
  336. msock.Send(HandShake());
  337. byte[] buffer = new byte[24];
  338. msock.Receive(buffer, SocketFlags.None);
  339. {
  340. Client = new byte[4];
  341. Client[0] = buffer[16];
  342. Client[1] = buffer[17];
  343. Client[2] = buffer[18];
  344. Client[3] = buffer[19];
  345. Server = new byte[4];
  346. Server[0] = buffer[20];
  347. Server[1] = buffer[21];
  348. Server[2] = buffer[22];
  349. Server[3] = buffer[23];
  350. }
  351. _isOpened = true;
  352. SetState(IoProviderStateEnum.Opened);
  353. LOG.Write(String.Format("连接PLC {0}:{1} 成功", _ip, _port));
  354. }
  355. catch (Exception ex)
  356. {
  357. _failedTrigger.CLK = true;
  358. if (_failedTrigger.Q)
  359. {
  360. LOG.Write(ex, String.Format("Communication failed with PLC {0}:{1}", _ip, _port));
  361. EV.PostMessage("System", EventEnum.DefaultWarning, String.Format("Communication failed with PLC {0}:{1}", _ip, _port));
  362. }
  363. _isOpened = false;
  364. SetState(IoProviderStateEnum.Uninitialized);
  365. return;
  366. }
  367. _failedTrigger.RST = true;
  368. _isOpened = true;
  369. return;
  370. }
  371. protected override void Close()
  372. {
  373. try
  374. {
  375. if (_isOpened)
  376. {
  377. _isOpened = false;
  378. msender.Close();
  379. }
  380. }
  381. catch (Exception ex)
  382. {
  383. LOG.Write(ex);
  384. }
  385. }
  386. protected override bool[] ReadDi(int offset, int size)
  387. {
  388. _timerRead.Start(0);
  389. try
  390. {
  391. byte[] data = new byte[200];
  392. ReadBlock<byte>(_diBlockType, (ushort)_diBlockStartPosition, (ushort)data.Length, ref data);
  393. double interval = _timerRead.GetElapseTime();
  394. if (interval > _averageWriteTime)
  395. {
  396. //LOG.Write(_ip + ":Max read PLC interval : " + interval);
  397. if (_averageReadTime < 0.1)
  398. _averageReadTime = interval;
  399. _averageReadTime = (interval + _averageReadTime) / 2;
  400. }
  401. return Array.ConvertAll(data, x => x == 1);
  402. }
  403. catch (Exception ex)
  404. {
  405. double interval = _timerRead.GetElapseTime();
  406. string detail = string.Empty;
  407. if(_receiveTimeout > 0 && _receiveTimeout <= interval)
  408. {
  409. detail = $"(timeout:{_receiveTimeout} ms, read time:{interval} ms)";
  410. }
  411. LOG.Error($"PLC ({_ip}) Read DI exception{detail}.", ex);
  412. EV.PostMessage("System", EventEnum.DefaultWarning, "PLC Read DI exception");
  413. Close();
  414. if (State != IoProviderStateEnum.Closing)
  415. SetState(IoProviderStateEnum.Uninitialized);
  416. }
  417. return null;
  418. }
  419. protected override bool[] ReadDO(int offset, int size)
  420. {
  421. if (_isDOLoaded) return null;
  422. _isDOLoaded = true;
  423. _timerRead.Start(0);
  424. try
  425. {
  426. LOG.Info($"{Module} {Name} PLC ({_ip}) start read DO");
  427. byte[] data = new byte[200];
  428. ReadBlock<byte>(_doBlockType, (ushort)_doBlockStartPosition, (ushort)data.Length, ref data);
  429. LOG.Info($"{Module} {Name} PLC ({_ip}) end read DO,result={string.Join(",", data)}");
  430. return Array.ConvertAll(data, x => x == 1);
  431. }
  432. catch (Exception ex)
  433. {
  434. double interval = _timerRead.GetElapseTime();
  435. string detail = string.Empty;
  436. if (_receiveTimeout > 0 && _receiveTimeout <= interval)
  437. {
  438. detail = $"(timeout:{_receiveTimeout} ms, read time:{interval} ms)";
  439. }
  440. LOG.Error($"PLC ({_ip}) Read DO exception{detail}.", ex);
  441. EV.PostMessage("System", EventEnum.DefaultWarning, "PLC Read DO exception");
  442. Close();
  443. if (State != IoProviderStateEnum.Closing)
  444. SetState(IoProviderStateEnum.Uninitialized);
  445. }
  446. return null;
  447. }
  448. protected override short[] ReadAi(int offset, int size)
  449. {
  450. _timerRead.Start(0);
  451. try
  452. {
  453. short[] data = new short[200];
  454. ReadBlock_short(_aiBlockType, (ushort)_aiBlockStartPosition, (ushort)data.Length, ref data);
  455. double interval = _timerRead.GetElapseTime();
  456. if (interval > _averageWriteTime)
  457. {
  458. //LOG.Write(_ip + ":Max read PLC interval : " + interval);
  459. if (_averageReadTime < 0.1)
  460. _averageReadTime = interval;
  461. _averageReadTime = (interval + _averageReadTime) / 2;
  462. }
  463. return data;
  464. }
  465. catch (Exception ex)
  466. {
  467. double interval = _timerRead.GetElapseTime();
  468. string detail = string.Empty;
  469. if (_receiveTimeout > 0 && _receiveTimeout <= interval) detail = $"(timeout:{_receiveTimeout} ms, read time:{interval} ms)";
  470. LOG.Error($"PLC ({_ip}) Read AI exception{detail}.", ex);
  471. EV.PostMessage("System", EventEnum.DefaultWarning, "PLC Read AI exception");
  472. Close();
  473. if (State != IoProviderStateEnum.Closing)
  474. SetState(IoProviderStateEnum.Uninitialized);
  475. }
  476. return null;
  477. }
  478. private Stopwatch stopwatchDo = new Stopwatch();
  479. protected override void WriteDo(int offset, bool[] buffer)
  480. {
  481. _timerWrite.Start(0);
  482. try
  483. {
  484. if (stopwatchDo.ElapsedMilliseconds > 500) LOG.Info($"PLC ({_ip}) From the end of the previous WriteDo to the start of the next WriteDO time interval:[{stopwatchDo.ElapsedMilliseconds}] ms ");
  485. if (stopwatchDo.ElapsedMilliseconds > 1000) EV.PostWarningLog("System", $"PLC ({_ip}) From the end of the previous WriteDo to the start of the next WriteDO time interval:[{stopwatchDo.ElapsedMilliseconds}] ms ");
  486. WriteBlock_Byte(_doBlockType, (ushort)_doBlockStartPosition, (ushort)buffer.Length, Array.ConvertAll(buffer, x => x ? (byte)1 : (byte)0));
  487. double interval = _timerWrite.GetElapseTime();
  488. if (interval > _averageWriteTime)
  489. {
  490. LOG.Write(_ip + ":Max write PLC interval : " + interval);
  491. if (_averageWriteTime < 0.1)
  492. _averageWriteTime = interval;
  493. _averageWriteTime = (_averageWriteTime + interval) / 2;
  494. }
  495. }
  496. catch (Exception ex)
  497. {
  498. double interval = _timerWrite.GetElapseTime();
  499. string detail = string.Empty;
  500. if (_sendTimeout > 0 && _sendTimeout <= interval) detail = $"(timeout:{_sendTimeout} ms, write time:{interval} ms)";
  501. LOG.Error($"PLC ({_ip}) Write DO exception{detail}.", ex);
  502. EV.PostMessage("System", EventEnum.DefaultWarning, "PLC Write DO exception");
  503. Close();
  504. if (State != IoProviderStateEnum.Closing)
  505. SetState(IoProviderStateEnum.Uninitialized);
  506. }
  507. stopwatchDo.Restart();
  508. }
  509. private Stopwatch stopwatchAo = new Stopwatch();
  510. protected override void WriteAo(int offset, short[] buffer)
  511. {
  512. _timerWrite.Start(0);
  513. try
  514. {
  515. if (stopwatchAo.ElapsedMilliseconds > 500) LOG.Info($"PLC ({_ip}) From the end of the previous WriteAO to the start of the next WriteAO time interval:[{stopwatchAo.ElapsedMilliseconds}] ms ");
  516. if (stopwatchAo.ElapsedMilliseconds > 1000 ) EV.PostWarningLog("System", $"PLC ({_ip}) From the end of the previous WriteAO to the start of the next WriteAO time interval:[{stopwatchAo.ElapsedMilliseconds}] ms");
  517. WriteBlock_short(_aoBlockType, (ushort)_aoBlockStartPosition, (ushort)buffer.Length, buffer);
  518. double interval = _timerWrite.GetElapseTime();
  519. if (interval > _averageWriteTime)
  520. {
  521. LOG.Write(_ip + ":Max write PLC interval : " + interval);
  522. if (_averageWriteTime < 0.1)
  523. _averageWriteTime = interval;
  524. _averageWriteTime = (_averageWriteTime + interval) / 2;
  525. }
  526. }
  527. catch (Exception ex)
  528. {
  529. double interval = _timerWrite.GetElapseTime();
  530. string detail = string.Empty;
  531. if (_sendTimeout > 0 && _sendTimeout <= interval) detail = $"(timeout:{_sendTimeout} ms, write time:{interval} ms)";
  532. LOG.Error($"PLC ({_ip}) Write AO exception{detail}.", ex);
  533. EV.PostMessage("System", EventEnum.DefaultWarning, "PLC Write AO exception");
  534. Close();
  535. if (State != IoProviderStateEnum.Closing)
  536. SetState(IoProviderStateEnum.Uninitialized);
  537. }
  538. stopwatchAo.Restart();
  539. }
  540. private void Send(byte[] content)
  541. {
  542. _sendTime.Start(0);
  543. msock.Send(content, SocketFlags.None);
  544. var curSendTime = _sendTime.GetElapseTime();
  545. if (_isOpened && curSendTime > _lastSendTime)
  546. {
  547. _lastSendTime = curSendTime;
  548. LOG.Write($"FinsPLC IP:{_ip}, send time:{curSendTime} ms");
  549. }
  550. if (curSendTime <= 50)
  551. {
  552. if (_sendTimeOkCount++ >= 3)
  553. {
  554. _lastSendTime = 200;
  555. }
  556. }
  557. else
  558. _sendTimeOkCount = 0;
  559. }
  560. private void Receive(byte[] buffer)
  561. {
  562. _receiveTime.Start(0);
  563. msock.Receive(buffer);
  564. var curReceiveTime = _receiveTime.GetElapseTime();
  565. if (_isOpened && curReceiveTime > _lastReceiveTime)
  566. {
  567. _lastReceiveTime = curReceiveTime;
  568. LOG.Write($"FinsPLC IP:{_ip}, receive time:{curReceiveTime} ms");
  569. }
  570. if (curReceiveTime <= 50)
  571. {
  572. if (_receiveTimeOkCount++ >= 3)
  573. {
  574. _lastReceiveTime = 200;
  575. }
  576. }
  577. else
  578. _receiveTimeOkCount = 0;
  579. }
  580. private void ReadBlock<T>(BlockType type, ushort addr, ushort len, ref T[] data)
  581. {
  582. byte[] FullCmd = new byte[34];
  583. //TCP FINS header
  584. FullCmd[0] = 0x46;//F
  585. FullCmd[1] = 0x49;//I
  586. FullCmd[2] = 0x4e;//N
  587. FullCmd[3] = 0x53;//S
  588. FullCmd[4] = 0;//cmd length
  589. FullCmd[5] = 0;
  590. FullCmd[6] = 0;
  591. FullCmd[7] = 0x1A;
  592. FullCmd[8] = 0;//frame command
  593. FullCmd[9] = 0;
  594. FullCmd[10] = 0;
  595. FullCmd[11] = 0x02;
  596. FullCmd[12] = 0;//err
  597. FullCmd[13] = 0;
  598. FullCmd[14] = 0;
  599. FullCmd[15] = 0;
  600. //command frame header
  601. FullCmd[16] = 0x80;//ICF
  602. FullCmd[17] = 0x00;//RSV
  603. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  604. FullCmd[19] = 0x00;//DNA, local network
  605. FullCmd[20] = Server[3];//DA1
  606. FullCmd[21] = 0x00;//DA2, CPU unit
  607. FullCmd[22] = 0x00;//SNA, local network
  608. FullCmd[23] = Client[3];//SA1
  609. FullCmd[24] = 0x00;//SA2, CPU unit
  610. FullCmd[25] = Convert.ToByte(21);//SID
  611. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  612. FullCmd[27] = 0x01; //Sub Request Code
  613. //Parameter
  614. FullCmd[28] = (byte)type;
  615. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  616. FullCmd[30] = (byte)(addr & 0xFF);
  617. FullCmd[31] = 0; //Bit Add
  618. FullCmd[32] = (byte)((len >> 8) & 0xFF); ; //Read Count
  619. FullCmd[33] = (byte)(len & 0xFF);
  620. //msock.Send(FullCmd, SocketFlags.None);
  621. Send(FullCmd);
  622. byte[] buffer = new byte[len + 30];
  623. //msock.Receive(buffer);
  624. Receive(buffer);
  625. bool Succeed = true;
  626. if (buffer[11] == 3)
  627. Succeed = CheckHeadError(buffer[15]);
  628. if (Succeed)//no header error
  629. {
  630. T[] buf = new T[len];
  631. Array.Copy(buffer, 30, buf, 0, len);
  632. if (CheckEndCode(buffer[28], buffer[29]))
  633. {
  634. for (int i = 0; i < len; i++)
  635. {
  636. data[i] = buf[i];
  637. }
  638. }
  639. }
  640. }
  641. private void ReadBlock_short(BlockType type, ushort addr, ushort len, ref short[] data)
  642. {
  643. byte[] FullCmd = new byte[34];
  644. //TCP FINS header
  645. FullCmd[0] = 0x46;//F
  646. FullCmd[1] = 0x49;//I
  647. FullCmd[2] = 0x4e;//N
  648. FullCmd[3] = 0x53;//S
  649. FullCmd[4] = 0;//cmd length
  650. FullCmd[5] = 0;
  651. FullCmd[6] = 0;
  652. FullCmd[7] = 0x1A;
  653. FullCmd[8] = 0;//frame command
  654. FullCmd[9] = 0;
  655. FullCmd[10] = 0;
  656. FullCmd[11] = 0x02;
  657. FullCmd[12] = 0;//err
  658. FullCmd[13] = 0;
  659. FullCmd[14] = 0;
  660. FullCmd[15] = 0;
  661. //command frame header
  662. FullCmd[16] = 0x80;//ICF
  663. FullCmd[17] = 0x00;//RSV
  664. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  665. FullCmd[19] = 0x00;//DNA, local network
  666. FullCmd[20] = Server[3];//DA1
  667. FullCmd[21] = 0x00;//DA2, CPU unit
  668. FullCmd[22] = 0x00;//SNA, local network
  669. FullCmd[23] = Client[3];//SA1
  670. FullCmd[24] = 0x00;//SA2, CPU unit
  671. FullCmd[25] = Convert.ToByte(21);//SID
  672. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  673. FullCmd[27] = 0x01; //Sub Request Code
  674. //Parameter
  675. FullCmd[28] = (byte)type;
  676. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  677. FullCmd[30] = (byte)(addr & 0xFF);
  678. FullCmd[31] = 0; //Bit Add
  679. int count = len;
  680. FullCmd[32] = (byte)((count >> 8) & 0xFF); ; //Read Count
  681. FullCmd[33] = (byte)(count & 0xFF);
  682. //msock.Send(FullCmd, SocketFlags.None);
  683. Send(FullCmd);
  684. byte[] buffer = new byte[31 + len * 2];
  685. //msock.Receive(buffer);
  686. Receive(buffer);
  687. bool Succeed = true;
  688. if (buffer[11] == 3)
  689. Succeed = CheckHeadError(buffer[15]);
  690. if (Succeed)//no header error
  691. {
  692. if (CheckEndCode(buffer[28], buffer[29]))
  693. {
  694. byte[] buf = new byte[2];
  695. for (int i = 0; i < len; i++)
  696. {
  697. buf[0] = buffer[30 + i * 2 + 1];
  698. buf[1] = buffer[30 + i * 2 + 0];
  699. data[i] = BitConverter.ToInt16(buf, 0);
  700. }
  701. }
  702. }
  703. }
  704. private void WriteBlock_Byte(BlockType type, ushort addr, ushort len, byte[] data)
  705. {
  706. byte[] FullCmd = new byte[34 + len];
  707. //TCP FINS header
  708. FullCmd[0] = 0x46;//F
  709. FullCmd[1] = 0x49;//I
  710. FullCmd[2] = 0x4e;//N
  711. FullCmd[3] = 0x53;//S
  712. int cmdLen = 26 + len;
  713. FullCmd[4] = 0;//cmd length
  714. FullCmd[5] = 0;
  715. FullCmd[6] = (byte)((cmdLen >> 8) & 0xFF);
  716. FullCmd[7] = (byte)(cmdLen & 0xFF);
  717. FullCmd[8] = 0;//frame command
  718. FullCmd[9] = 0;
  719. FullCmd[10] = 0;
  720. FullCmd[11] = 0x02;
  721. FullCmd[12] = 0;//err
  722. FullCmd[13] = 0;
  723. FullCmd[14] = 0;
  724. FullCmd[15] = 0;
  725. //command frame header
  726. FullCmd[16] = 0x80;//ICF
  727. FullCmd[17] = 0x00;//RSV
  728. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  729. FullCmd[19] = 0x00;//DNA, local network
  730. FullCmd[20] = Server[3];//DA1
  731. FullCmd[21] = 0x00;//DA2, CPU unit
  732. FullCmd[22] = 0x00;//SNA, local network
  733. FullCmd[23] = Client[3];//SA1
  734. FullCmd[24] = 0x00;//SA2, CPU unit
  735. FullCmd[25] = Convert.ToByte(21);//SID
  736. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  737. FullCmd[27] = 0x02; //Sub Request Code
  738. //Parameter
  739. FullCmd[28] = (byte)type;
  740. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  741. FullCmd[30] = (byte)(addr & 0xFF);
  742. FullCmd[31] = 0; //Bit Add
  743. FullCmd[32] = (byte)((len >> 8) & 0xFF); ; //Write Count
  744. FullCmd[33] = (byte)(len & 0xFF);
  745. for (int i = 0; i < len; i++)
  746. {
  747. FullCmd[34 + i] = data[i];
  748. }
  749. //msock.Send(FullCmd, SocketFlags.None);
  750. Send(FullCmd);
  751. byte[] buffer = new byte[len + 34];
  752. //msock.Receive(buffer);
  753. Receive(buffer);
  754. bool Succeed = true;
  755. if (buffer[11] == 3)
  756. Succeed = CheckHeadError(buffer[15]);
  757. if (Succeed)//no header error
  758. {
  759. if (CheckEndCode(buffer[28], buffer[29]))
  760. {
  761. //do nothing
  762. }
  763. }
  764. }
  765. private void WriteBlock_short(BlockType type, ushort addr, ushort len, short[] data)
  766. {
  767. byte[] FullCmd = new byte[34 + len * 2];
  768. //TCP FINS header
  769. FullCmd[0] = 0x46;//F
  770. FullCmd[1] = 0x49;//I
  771. FullCmd[2] = 0x4e;//N
  772. FullCmd[3] = 0x53;//S
  773. int cmdLen = 26 + len * 2;
  774. FullCmd[4] = 0;//cmd length
  775. FullCmd[5] = 0;
  776. FullCmd[6] = (byte)((cmdLen >> 8) & 0xFF);
  777. FullCmd[7] = (byte)(cmdLen & 0xFF);
  778. FullCmd[8] = 0;//frame command
  779. FullCmd[9] = 0;
  780. FullCmd[10] = 0;
  781. FullCmd[11] = 0x02;
  782. FullCmd[12] = 0;//err
  783. FullCmd[13] = 0;
  784. FullCmd[14] = 0;
  785. FullCmd[15] = 0;
  786. //command frame header
  787. FullCmd[16] = 0x80;//ICF
  788. FullCmd[17] = 0x00;//RSV
  789. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  790. FullCmd[19] = 0x00;//DNA, local network
  791. FullCmd[20] = Server[3];//DA1
  792. FullCmd[21] = 0x00;//DA2, CPU unit
  793. FullCmd[22] = 0x00;//SNA, local network
  794. FullCmd[23] = Client[3];//SA1
  795. FullCmd[24] = 0x00;//SA2, CPU unit
  796. FullCmd[25] = Convert.ToByte(21);//SID
  797. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  798. FullCmd[27] = 0x02; //Sub Request Code
  799. //Parameter
  800. FullCmd[28] = (byte)type;
  801. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  802. FullCmd[30] = (byte)(addr & 0xFF);
  803. FullCmd[31] = 0; //Bit Add
  804. int count = len;
  805. FullCmd[32] = (byte)((count >> 8) & 0xFF); ; //Write Count
  806. FullCmd[33] = (byte)(count & 0xFF);
  807. try
  808. {
  809. for (int i = 0; i < len; i++)
  810. {
  811. byte[] buf = BitConverter.GetBytes(data[i]);
  812. FullCmd[34 + i * 2 + 0] = buf[1];
  813. FullCmd[34 + i * 2 + 1] = buf[0];
  814. }
  815. }
  816. catch (Exception ex)
  817. {
  818. LOG.Write(ex);
  819. }
  820. //msock.Send(FullCmd, SocketFlags.None);
  821. Send(FullCmd);
  822. byte[] buffer = new byte[31 + len * 2];
  823. //msock.Receive(buffer);
  824. Receive(buffer);
  825. bool Succeed = true;
  826. if (buffer[11] == 3)
  827. Succeed = CheckHeadError(buffer[15]);
  828. if (Succeed)//no header error
  829. {
  830. if (CheckEndCode(buffer[28], buffer[29]))
  831. {
  832. //do nothing
  833. }
  834. }
  835. }
  836. private byte[] HandShake()
  837. {
  838. //handshake
  839. byte[] Handshake = new byte[20];
  840. Handshake[0] = 0x46;
  841. Handshake[1] = 0x49;
  842. Handshake[2] = 0x4e;
  843. Handshake[3] = 0x53;
  844. Handshake[4] = 0;
  845. Handshake[5] = 0;
  846. Handshake[6] = 0;
  847. Handshake[7] = 0x0c;
  848. Handshake[8] = 0;
  849. Handshake[9] = 0;
  850. Handshake[10] = 0;
  851. Handshake[11] = 0;
  852. Handshake[12] = 0;
  853. Handshake[13] = 0;
  854. Handshake[14] = 0;
  855. Handshake[15] = 0;
  856. Handshake[16] = 0;
  857. Handshake[17] = 0;
  858. Handshake[18] = 0;
  859. Handshake[19] = 0;//ask for client and server node number, the client node will allocated automatically
  860. return Handshake;
  861. }
  862. /// <summary>
  863. /// (若返回的头指令为3)检查命令头中的错误代码
  864. /// </summary>
  865. /// <param name="Code">错误代码</param>
  866. /// <returns>指示程序是否可以继续进行</returns>
  867. bool CheckHeadError(byte Code)
  868. {
  869. switch (Code)
  870. {
  871. case 0x00: return true;
  872. case 0x01: RaiseException("the head is not 'FINS'"); return false;
  873. case 0x02: RaiseException("the data length is too long"); return false;
  874. case 0x03: RaiseException("the command is not supported"); return false;
  875. }
  876. //no hit
  877. RaiseException("unknown exception"); return false;
  878. }
  879. private void RaiseException(string p)
  880. {
  881. _isOpened = false;
  882. }
  883. /// <summary>
  884. /// 检查命令帧中的EndCode
  885. /// </summary>
  886. /// <param name="Main">主码</param>
  887. /// <param name="Sub">副码</param>
  888. /// <returns>指示程序是否可以继续进行</returns>
  889. bool CheckEndCode(byte Main, byte Sub)
  890. {
  891. switch (Main)
  892. {
  893. case 0x00:
  894. switch (Sub)
  895. {
  896. case 0x00: return true;//the only situation of success
  897. case 0x01: RaiseException("service canceled"); return false;
  898. }
  899. break;
  900. case 0x01:
  901. switch (Sub)
  902. {
  903. case 0x01: RaiseException("local node not in network"); return false;
  904. case 0x02: RaiseException("token timeout"); return false;
  905. case 0x03: RaiseException("retries failed"); return false;
  906. case 0x04: RaiseException("too many send frames"); return false;
  907. case 0x05: RaiseException("node address range error"); return false;
  908. case 0x06: RaiseException("node address duplication"); return false;
  909. }
  910. break;
  911. case 0x02:
  912. switch (Sub)
  913. {
  914. case 0x01: RaiseException("destination node not in network"); return false;
  915. case 0x02: RaiseException("unit missing"); return false;
  916. case 0x03: RaiseException("third node missing"); return false;
  917. case 0x04: RaiseException("destination node busy"); return false;
  918. case 0x05: RaiseException("response timeout"); return false;
  919. }
  920. break;
  921. case 0x03:
  922. switch (Sub)
  923. {
  924. case 0x01: RaiseException("communications controller error"); return false;
  925. case 0x02: RaiseException("CPU unit error"); return false;
  926. case 0x03: RaiseException("controller error"); return false;
  927. case 0x04: RaiseException("unit number error"); return false;
  928. }
  929. break;
  930. case 0x04:
  931. switch (Sub)
  932. {
  933. case 0x01: RaiseException("undefined command"); return false;
  934. case 0x02: RaiseException("not supported by model/version"); return false;
  935. }
  936. break;
  937. case 0x05:
  938. switch (Sub)
  939. {
  940. case 0x01: RaiseException("destination address setting error"); return false;
  941. case 0x02: RaiseException("no routing tables"); return false;
  942. case 0x03: RaiseException("routing table error"); return false;
  943. case 0x04: RaiseException("too many relays"); return false;
  944. }
  945. break;
  946. case 0x10:
  947. switch (Sub)
  948. {
  949. case 0x01: RaiseException("command too long"); return false;
  950. case 0x02: RaiseException("command too short"); return false;
  951. case 0x03: RaiseException("elements/data don't match"); return false;
  952. case 0x04: RaiseException("command format error"); return false;
  953. case 0x05: RaiseException("header error"); return false;
  954. }
  955. break;
  956. case 0x11:
  957. switch (Sub)
  958. {
  959. case 0x01: RaiseException("area classification missing"); return false;
  960. case 0x02: RaiseException("access size error"); return false;
  961. case 0x03: RaiseException("address range error"); return false;
  962. case 0x04: RaiseException("address range exceeded"); return false;
  963. case 0x06: RaiseException("program missing"); return false;
  964. case 0x09: RaiseException("relational error"); return false;
  965. case 0x0a: RaiseException("duplicate data access"); return false;
  966. case 0x0b: RaiseException("response too long"); return false;
  967. case 0x0c: RaiseException("parameter error"); return false;
  968. }
  969. break;
  970. case 0x20:
  971. switch (Sub)
  972. {
  973. case 0x02: RaiseException("protected"); return false;
  974. case 0x03: RaiseException("table missing"); return false;
  975. case 0x04: RaiseException("data missing"); return false;
  976. case 0x05: RaiseException("program missing"); return false;
  977. case 0x06: RaiseException("file missing"); return false;
  978. case 0x07: RaiseException("data mismatch"); return false;
  979. }
  980. break;
  981. case 0x21:
  982. switch (Sub)
  983. {
  984. case 0x01: RaiseException("read-only"); return false;
  985. case 0x02: RaiseException("protected , cannot write data link table"); return false;
  986. case 0x03: RaiseException("cannot register"); return false;
  987. case 0x05: RaiseException("program missing"); return false;
  988. case 0x06: RaiseException("file missing"); return false;
  989. case 0x07: RaiseException("file name already exists"); return false;
  990. case 0x08: RaiseException("cannot change"); return false;
  991. }
  992. break;
  993. case 0x22:
  994. switch (Sub)
  995. {
  996. case 0x01: RaiseException("not possible during execution"); return false;
  997. case 0x02: RaiseException("not possible while running"); return false;
  998. case 0x03: RaiseException("wrong PLC mode"); return false;
  999. case 0x04: RaiseException("wrong PLC mode"); return false;
  1000. case 0x05: RaiseException("wrong PLC mode"); return false;
  1001. case 0x06: RaiseException("wrong PLC mode"); return false;
  1002. case 0x07: RaiseException("specified node not polling node"); return false;
  1003. case 0x08: RaiseException("step cannot be executed"); return false;
  1004. }
  1005. break;
  1006. case 0x23:
  1007. switch (Sub)
  1008. {
  1009. case 0x01: RaiseException("file device missing"); return false;
  1010. case 0x02: RaiseException("memory missing"); return false;
  1011. case 0x03: RaiseException("clock missing"); return false;
  1012. }
  1013. break;
  1014. case 0x24:
  1015. switch (Sub)
  1016. { case 0x01: RaiseException("table missing"); return false; }
  1017. break;
  1018. case 0x25:
  1019. switch (Sub)
  1020. {
  1021. case 0x02: RaiseException("memory error"); return false;
  1022. case 0x03: RaiseException("I/O setting error"); return false;
  1023. case 0x04: RaiseException("too many I/O points"); return false;
  1024. case 0x05: RaiseException("CPU bus error"); return false;
  1025. case 0x06: RaiseException("I/O duplication"); return false;
  1026. case 0x07: RaiseException("CPU bus error"); return false;
  1027. case 0x09: RaiseException("SYSMAC BUS/2 error"); return false;
  1028. case 0x0a: RaiseException("CPU bus unit error"); return false;
  1029. case 0x0d: RaiseException("SYSMAC BUS No. duplication"); return false;
  1030. case 0x0f: RaiseException("memory error"); return false;
  1031. case 0x10: RaiseException("SYSMAC BUS terminator missing"); return false;
  1032. }
  1033. break;
  1034. case 0x26:
  1035. switch (Sub)
  1036. {
  1037. case 0x01: RaiseException("no protection"); return false;
  1038. case 0x02: RaiseException("incorrect password"); return false;
  1039. case 0x04: RaiseException("protected"); return false;
  1040. case 0x05: RaiseException("service already executing"); return false;
  1041. case 0x06: RaiseException("service stopped"); return false;
  1042. case 0x07: RaiseException("no execution right"); return false;
  1043. case 0x08: RaiseException("settings required before execution"); return false;
  1044. case 0x09: RaiseException("necessary items not set"); return false;
  1045. case 0x0a: RaiseException("number already defined"); return false;
  1046. case 0x0b: RaiseException("error will not clear"); return false;
  1047. }
  1048. break;
  1049. case 0x30:
  1050. switch (Sub)
  1051. { case 0x01: RaiseException("no access right"); return false; }
  1052. break;
  1053. case 0x40:
  1054. switch (Sub)
  1055. { case 0x01: RaiseException("service aborted"); return false; }
  1056. break;
  1057. }
  1058. //no hit
  1059. RaiseException("unknown exception"); return false;
  1060. }
  1061. }
  1062. }