FinsPlc.cs 41 KB

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