FinsPlc.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  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 CyberX8_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. protected 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. }
  345. }
  346. catch (Exception ex)
  347. {
  348. LOG.WriteExeption(ex);
  349. }
  350. }
  351. protected override bool[] ReadDi(int offset, int size)
  352. {
  353. try
  354. {
  355. byte[] data = new byte[200];
  356. double interval = _timerRead.GetElapseTime();
  357. if (interval > _averageWriteTime)
  358. {
  359. //LOG.Write(_ip + ":Max read PLC interval : " + interval);
  360. if (_averageReadTime < 0.1)
  361. _averageReadTime = interval;
  362. _averageReadTime = (interval + _averageReadTime) / 2;
  363. }
  364. ReadBlock<byte>(_diBlockType, (ushort)_diBlockStartPosition, (ushort)data.Length, ref data);
  365. _timerRead.Start(0);
  366. return Array.ConvertAll(data, x => x == 1);
  367. }
  368. catch (Exception ex)
  369. {
  370. LOG.WriteExeption(String.Format("PLC ({0}) Read exception.", _ip), ex);
  371. Close();
  372. }
  373. return null;
  374. }
  375. protected override short[] ReadAi(int offset, int size)
  376. {
  377. try
  378. {
  379. short[] data = new short[200];
  380. double interval = _timerRead.GetElapseTime();
  381. if (interval > _averageWriteTime)
  382. {
  383. //LOG.Write(_ip + ":Max read PLC interval : " + interval);
  384. if (_averageReadTime < 0.1)
  385. _averageReadTime = interval;
  386. _averageReadTime = (interval + _averageReadTime) / 2;
  387. }
  388. ReadBlock_short(_aiBlockType, (ushort)_aiBlockStartPosition, (ushort)data.Length, ref data);
  389. _timerRead.Start(0);
  390. return data;
  391. }
  392. catch (Exception ex)
  393. {
  394. LOG.WriteExeption(String.Format("PLC ({0}) Read exception.", _ip), ex);
  395. Close();
  396. }
  397. return null;
  398. }
  399. protected override void WriteDo(int offset, bool[] buffer)
  400. {
  401. try
  402. {
  403. _timerWrite.Start(0);
  404. WriteBlock_Byte(_doBlockType, (ushort)_doBlockStartPosition, (ushort)buffer.Length, Array.ConvertAll(buffer, x=>x?(byte)1: (byte)0));
  405. double interval = _timerWrite.GetElapseTime();
  406. if (interval > _averageWriteTime)
  407. {
  408. //LOG.Write(_ip + ":Max write PLC interval : " + interval);
  409. if (_averageWriteTime < 0.1)
  410. _averageWriteTime = interval;
  411. _averageWriteTime = (_averageWriteTime + interval) / 2;
  412. }
  413. return ;
  414. }
  415. catch (Exception ex)
  416. {
  417. LOG.WriteExeption(String.Format("PLC ({0})Write exception.", _ip), ex);
  418. Close();
  419. return ;
  420. }
  421. }
  422. protected override void WriteAo(int offset, short[] buffer)
  423. {
  424. try
  425. {
  426. _timerWrite.Start(0);
  427. WriteBlock_short(_aoBlockType, (ushort)_aoBlockStartPosition, (ushort)buffer.Length, buffer);
  428. double interval = _timerWrite.GetElapseTime();
  429. if (interval > _averageWriteTime)
  430. {
  431. //LOG.Write(_ip + ":Max write PLC interval : " + interval);
  432. if (_averageWriteTime < 0.1)
  433. _averageWriteTime = interval;
  434. _averageWriteTime = (_averageWriteTime + interval) / 2;
  435. }
  436. return ;
  437. }
  438. catch (Exception ex)
  439. {
  440. LOG.WriteExeption(String.Format("PLC ({0})Write exception.", _ip), ex);
  441. Close();
  442. return ;
  443. }
  444. }
  445. private void ReadBlock<T>(BlockType type, ushort addr, ushort len, ref T[] data)
  446. {
  447. byte[] FullCmd = new byte[34];
  448. //TCP FINS header
  449. FullCmd[0] = 0x46;//F
  450. FullCmd[1] = 0x49;//I
  451. FullCmd[2] = 0x4e;//N
  452. FullCmd[3] = 0x53;//S
  453. FullCmd[4] = 0;//cmd length
  454. FullCmd[5] = 0;
  455. FullCmd[6] = 0;
  456. FullCmd[7] = 0x1A;
  457. FullCmd[8] = 0;//frame command
  458. FullCmd[9] = 0;
  459. FullCmd[10] = 0;
  460. FullCmd[11] = 0x02;
  461. FullCmd[12] = 0;//err
  462. FullCmd[13] = 0;
  463. FullCmd[14] = 0;
  464. FullCmd[15] = 0;
  465. //command frame header
  466. FullCmd[16] = 0x80;//ICF
  467. FullCmd[17] = 0x00;//RSV
  468. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  469. FullCmd[19] = 0x00;//DNA, local network
  470. FullCmd[20] = Server[3];//DA1
  471. FullCmd[21] = 0x00;//DA2, CPU unit
  472. FullCmd[22] = 0x00;//SNA, local network
  473. FullCmd[23] = Client[3];//SA1
  474. FullCmd[24] = 0x00;//SA2, CPU unit
  475. FullCmd[25] = Convert.ToByte(21);//SID
  476. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  477. FullCmd[27] = 0x01; //Sub Request Code
  478. //Parameter
  479. FullCmd[28] = (byte)type;
  480. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  481. FullCmd[30] = (byte)(addr & 0xFF);
  482. FullCmd[31] = 0; //Bit Add
  483. FullCmd[32] = (byte)((len >> 8) & 0xFF); ; //Read Count
  484. FullCmd[33] = (byte)(len & 0xFF);
  485. msock.Send(FullCmd, SocketFlags.None);
  486. byte[] buffer = new byte[len + 30];
  487. msock.Receive(buffer);
  488. bool Succeed = true;
  489. if (buffer[11] == 3)
  490. Succeed = CheckHeadError(buffer[15]);
  491. if (Succeed)//no header error
  492. {
  493. T[] buf = new T[len];
  494. Array.Copy(buffer, 30, buf, 0, len);
  495. if (CheckEndCode(buffer[28], buffer[29]))
  496. {
  497. for (int i = 0; i < len; i++)
  498. {
  499. data[i] = buf[i];
  500. }
  501. }
  502. }
  503. }
  504. private void ReadBlock_short(BlockType type, ushort addr, ushort len, ref short[] data)
  505. {
  506. byte[] FullCmd = new byte[34];
  507. //TCP FINS header
  508. FullCmd[0] = 0x46;//F
  509. FullCmd[1] = 0x49;//I
  510. FullCmd[2] = 0x4e;//N
  511. FullCmd[3] = 0x53;//S
  512. FullCmd[4] = 0;//cmd length
  513. FullCmd[5] = 0;
  514. FullCmd[6] = 0;
  515. FullCmd[7] = 0x1A;
  516. FullCmd[8] = 0;//frame command
  517. FullCmd[9] = 0;
  518. FullCmd[10] = 0;
  519. FullCmd[11] = 0x02;
  520. FullCmd[12] = 0;//err
  521. FullCmd[13] = 0;
  522. FullCmd[14] = 0;
  523. FullCmd[15] = 0;
  524. //command frame header
  525. FullCmd[16] = 0x80;//ICF
  526. FullCmd[17] = 0x00;//RSV
  527. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  528. FullCmd[19] = 0x00;//DNA, local network
  529. FullCmd[20] = Server[3];//DA1
  530. FullCmd[21] = 0x00;//DA2, CPU unit
  531. FullCmd[22] = 0x00;//SNA, local network
  532. FullCmd[23] = Client[3];//SA1
  533. FullCmd[24] = 0x00;//SA2, CPU unit
  534. FullCmd[25] = Convert.ToByte(21);//SID
  535. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  536. FullCmd[27] = 0x01; //Sub Request Code
  537. //Parameter
  538. FullCmd[28] = (byte)type;
  539. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  540. FullCmd[30] = (byte)(addr & 0xFF);
  541. FullCmd[31] = 0; //Bit Add
  542. int count = len ;
  543. FullCmd[32] = (byte)((count >> 8) & 0xFF); ; //Read Count
  544. FullCmd[33] = (byte)(count & 0xFF);
  545. msock.Send(FullCmd, SocketFlags.None);
  546. byte[] buffer = new byte[31 + len * 2];
  547. msock.Receive(buffer);
  548. bool Succeed = true;
  549. if (buffer[11] == 3)
  550. Succeed = CheckHeadError(buffer[15]);
  551. if (Succeed)//no header error
  552. {
  553. if (CheckEndCode(buffer[28], buffer[29]))
  554. {
  555. byte[] buf = new byte[2];
  556. for (int i = 0; i < len; i++)
  557. {
  558. buf[0] = buffer[30 + i * 2 + 1];
  559. buf[1] = buffer[30 + i * 2 + 0];
  560. data[i] = BitConverter.ToInt16(buf, 0);
  561. }
  562. }
  563. }
  564. }
  565. private void WriteBlock_Byte(BlockType type, ushort addr, ushort len, byte[] data)
  566. {
  567. byte[] FullCmd = new byte[34 + len];
  568. //TCP FINS header
  569. FullCmd[0] = 0x46;//F
  570. FullCmd[1] = 0x49;//I
  571. FullCmd[2] = 0x4e;//N
  572. FullCmd[3] = 0x53;//S
  573. int cmdLen = 26 + len;
  574. FullCmd[4] = 0;//cmd length
  575. FullCmd[5] = 0;
  576. FullCmd[6] = (byte)((cmdLen >> 8) & 0xFF);
  577. FullCmd[7] = (byte)(cmdLen & 0xFF);
  578. FullCmd[8] = 0;//frame command
  579. FullCmd[9] = 0;
  580. FullCmd[10] = 0;
  581. FullCmd[11] = 0x02;
  582. FullCmd[12] = 0;//err
  583. FullCmd[13] = 0;
  584. FullCmd[14] = 0;
  585. FullCmd[15] = 0;
  586. //command frame header
  587. FullCmd[16] = 0x80;//ICF
  588. FullCmd[17] = 0x00;//RSV
  589. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  590. FullCmd[19] = 0x00;//DNA, local network
  591. FullCmd[20] = Server[3];//DA1
  592. FullCmd[21] = 0x00;//DA2, CPU unit
  593. FullCmd[22] = 0x00;//SNA, local network
  594. FullCmd[23] = Client[3];//SA1
  595. FullCmd[24] = 0x00;//SA2, CPU unit
  596. FullCmd[25] = Convert.ToByte(21);//SID
  597. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  598. FullCmd[27] = 0x02; //Sub Request Code
  599. //Parameter
  600. FullCmd[28] = (byte)type;
  601. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  602. FullCmd[30] = (byte)(addr & 0xFF);
  603. FullCmd[31] = 0; //Bit Add
  604. FullCmd[32] = (byte)((len >> 8) & 0xFF); ; //Write Count
  605. FullCmd[33] = (byte)(len & 0xFF);
  606. for (int i = 0; i < len; i++)
  607. {
  608. FullCmd[34 + i] = data[i];
  609. }
  610. msock.Send(FullCmd, SocketFlags.None);
  611. byte[] buffer = new byte[len + 34];
  612. msock.Receive(buffer);
  613. bool Succeed = true;
  614. if (buffer[11] == 3)
  615. Succeed = CheckHeadError(buffer[15]);
  616. if (Succeed)//no header error
  617. {
  618. if (CheckEndCode(buffer[28], buffer[29]))
  619. {
  620. //do nothing
  621. }
  622. }
  623. }
  624. private void WriteBlock_short(BlockType type, ushort addr, ushort len, short[] data)
  625. {
  626. byte[] FullCmd = new byte[34 + len * 2];
  627. //TCP FINS header
  628. FullCmd[0] = 0x46;//F
  629. FullCmd[1] = 0x49;//I
  630. FullCmd[2] = 0x4e;//N
  631. FullCmd[3] = 0x53;//S
  632. int cmdLen = 26 + len * 2;
  633. FullCmd[4] = 0;//cmd length
  634. FullCmd[5] = 0;
  635. FullCmd[6] = (byte)((cmdLen >> 8) & 0xFF);
  636. FullCmd[7] = (byte)(cmdLen & 0xFF);
  637. FullCmd[8] = 0;//frame command
  638. FullCmd[9] = 0;
  639. FullCmd[10] = 0;
  640. FullCmd[11] = 0x02;
  641. FullCmd[12] = 0;//err
  642. FullCmd[13] = 0;
  643. FullCmd[14] = 0;
  644. FullCmd[15] = 0;
  645. //command frame header
  646. FullCmd[16] = 0x80;//ICF
  647. FullCmd[17] = 0x00;//RSV
  648. FullCmd[18] = 0x02;//GCT, less than 8 network layers
  649. FullCmd[19] = 0x00;//DNA, local network
  650. FullCmd[20] = Server[3];//DA1
  651. FullCmd[21] = 0x00;//DA2, CPU unit
  652. FullCmd[22] = 0x00;//SNA, local network
  653. FullCmd[23] = Client[3];//SA1
  654. FullCmd[24] = 0x00;//SA2, CPU unit
  655. FullCmd[25] = Convert.ToByte(21);//SID
  656. FullCmd[26] = 0x01; //FINS CMD Main Request Code 0101 Read IO Area
  657. FullCmd[27] = 0x02; //Sub Request Code
  658. //Parameter
  659. FullCmd[28] = (byte)type;
  660. FullCmd[29] = (byte)((addr >> 8) & 0xFF); //Block Add
  661. FullCmd[30] = (byte)(addr & 0xFF);
  662. FullCmd[31] = 0; //Bit Add
  663. int count = len ;
  664. FullCmd[32] = (byte)((count >> 8) & 0xFF); ; //Write Count
  665. FullCmd[33] = (byte)(count & 0xFF);
  666. try
  667. {
  668. for (int i = 0; i < len; i++)
  669. {
  670. byte[] buf = BitConverter.GetBytes(data[i]);
  671. FullCmd[34 + i * 2 + 0] = buf[1];
  672. FullCmd[34 + i * 2 + 1] = buf[0];
  673. }
  674. }
  675. catch (Exception ex)
  676. {
  677. LOG.WriteExeption(ex);
  678. }
  679. msock.Send(FullCmd, SocketFlags.None);
  680. byte[] buffer = new byte[31 + len * 2];
  681. msock.Receive(buffer);
  682. bool Succeed = true;
  683. if (buffer[11] == 3)
  684. Succeed = CheckHeadError(buffer[15]);
  685. if (Succeed)//no header error
  686. {
  687. if (CheckEndCode(buffer[28], buffer[29]))
  688. {
  689. //do nothing
  690. }
  691. }
  692. }
  693. private byte[] HandShake()
  694. {
  695. //handshake
  696. byte[] Handshake = new byte[20];
  697. Handshake[0] = 0x46;
  698. Handshake[1] = 0x49;
  699. Handshake[2] = 0x4e;
  700. Handshake[3] = 0x53;
  701. Handshake[4] = 0;
  702. Handshake[5] = 0;
  703. Handshake[6] = 0;
  704. Handshake[7] = 0x0c;
  705. Handshake[8] = 0;
  706. Handshake[9] = 0;
  707. Handshake[10] = 0;
  708. Handshake[11] = 0;
  709. Handshake[12] = 0;
  710. Handshake[13] = 0;
  711. Handshake[14] = 0;
  712. Handshake[15] = 0;
  713. Handshake[16] = 0;
  714. Handshake[17] = 0;
  715. Handshake[18] = 0;
  716. Handshake[19] = 0;//ask for client and server node number, the client node will allocated automatically
  717. return Handshake;
  718. }
  719. /// <summary>
  720. /// (若返回的头指令为3)检查命令头中的错误代码
  721. /// </summary>
  722. /// <param name="Code">错误代码</param>
  723. /// <returns>指示程序是否可以继续进行</returns>
  724. bool CheckHeadError(byte Code)
  725. {
  726. switch (Code)
  727. {
  728. case 0x00: return true;
  729. case 0x01: RaiseException("the head is not 'FINS'"); return false;
  730. case 0x02: RaiseException("the data length is too long"); return false;
  731. case 0x03: RaiseException("the command is not supported"); return false;
  732. }
  733. //no hit
  734. RaiseException("unknown exception"); return false;
  735. }
  736. private void RaiseException(string p)
  737. {
  738. _isOpened = false;
  739. }
  740. /// <summary>
  741. /// 检查命令帧中的EndCode
  742. /// </summary>
  743. /// <param name="Main">主码</param>
  744. /// <param name="Sub">副码</param>
  745. /// <returns>指示程序是否可以继续进行</returns>
  746. bool CheckEndCode(byte Main, byte Sub)
  747. {
  748. switch (Main)
  749. {
  750. case 0x00:
  751. switch (Sub)
  752. {
  753. case 0x00: return true;//the only situation of success
  754. case 0x01: RaiseException("service canceled"); return false;
  755. }
  756. break;
  757. case 0x01:
  758. switch (Sub)
  759. {
  760. case 0x01: RaiseException("local node not in network"); return false;
  761. case 0x02: RaiseException("token timeout"); return false;
  762. case 0x03: RaiseException("retries failed"); return false;
  763. case 0x04: RaiseException("too many send frames"); return false;
  764. case 0x05: RaiseException("node address range error"); return false;
  765. case 0x06: RaiseException("node address duplication"); return false;
  766. }
  767. break;
  768. case 0x02:
  769. switch (Sub)
  770. {
  771. case 0x01: RaiseException("destination node not in network"); return false;
  772. case 0x02: RaiseException("unit missing"); return false;
  773. case 0x03: RaiseException("third node missing"); return false;
  774. case 0x04: RaiseException("destination node busy"); return false;
  775. case 0x05: RaiseException("response timeout"); return false;
  776. }
  777. break;
  778. case 0x03:
  779. switch (Sub)
  780. {
  781. case 0x01: RaiseException("communications controller error"); return false;
  782. case 0x02: RaiseException("CPU unit error"); return false;
  783. case 0x03: RaiseException("controller error"); return false;
  784. case 0x04: RaiseException("unit number error"); return false;
  785. }
  786. break;
  787. case 0x04:
  788. switch (Sub)
  789. {
  790. case 0x01: RaiseException("undefined command"); return false;
  791. case 0x02: RaiseException("not supported by model/version"); return false;
  792. }
  793. break;
  794. case 0x05:
  795. switch (Sub)
  796. {
  797. case 0x01: RaiseException("destination address setting error"); return false;
  798. case 0x02: RaiseException("no routing tables"); return false;
  799. case 0x03: RaiseException("routing table error"); return false;
  800. case 0x04: RaiseException("too many relays"); return false;
  801. }
  802. break;
  803. case 0x10:
  804. switch (Sub)
  805. {
  806. case 0x01: RaiseException("command too long"); return false;
  807. case 0x02: RaiseException("command too short"); return false;
  808. case 0x03: RaiseException("elements/data don't match"); return false;
  809. case 0x04: RaiseException("command format error"); return false;
  810. case 0x05: RaiseException("header error"); return false;
  811. }
  812. break;
  813. case 0x11:
  814. switch (Sub)
  815. {
  816. case 0x01: RaiseException("area classification missing"); return false;
  817. case 0x02: RaiseException("access size error"); return false;
  818. case 0x03: RaiseException("address range error"); return false;
  819. case 0x04: RaiseException("address range exceeded"); return false;
  820. case 0x06: RaiseException("program missing"); return false;
  821. case 0x09: RaiseException("relational error"); return false;
  822. case 0x0a: RaiseException("duplicate data access"); return false;
  823. case 0x0b: RaiseException("response too long"); return false;
  824. case 0x0c: RaiseException("parameter error"); return false;
  825. }
  826. break;
  827. case 0x20:
  828. switch (Sub)
  829. {
  830. case 0x02: RaiseException("protected"); return false;
  831. case 0x03: RaiseException("table missing"); return false;
  832. case 0x04: RaiseException("data missing"); return false;
  833. case 0x05: RaiseException("program missing"); return false;
  834. case 0x06: RaiseException("file missing"); return false;
  835. case 0x07: RaiseException("data mismatch"); return false;
  836. }
  837. break;
  838. case 0x21:
  839. switch (Sub)
  840. {
  841. case 0x01: RaiseException("read-only"); return false;
  842. case 0x02: RaiseException("protected , cannot write data link table"); return false;
  843. case 0x03: RaiseException("cannot register"); return false;
  844. case 0x05: RaiseException("program missing"); return false;
  845. case 0x06: RaiseException("file missing"); return false;
  846. case 0x07: RaiseException("file name already exists"); return false;
  847. case 0x08: RaiseException("cannot change"); return false;
  848. }
  849. break;
  850. case 0x22:
  851. switch (Sub)
  852. {
  853. case 0x01: RaiseException("not possible during execution"); return false;
  854. case 0x02: RaiseException("not possible while running"); return false;
  855. case 0x03: RaiseException("wrong PLC mode"); return false;
  856. case 0x04: RaiseException("wrong PLC mode"); return false;
  857. case 0x05: RaiseException("wrong PLC mode"); return false;
  858. case 0x06: RaiseException("wrong PLC mode"); return false;
  859. case 0x07: RaiseException("specified node not polling node"); return false;
  860. case 0x08: RaiseException("step cannot be executed"); return false;
  861. }
  862. break;
  863. case 0x23:
  864. switch (Sub)
  865. {
  866. case 0x01: RaiseException("file device missing"); return false;
  867. case 0x02: RaiseException("memory missing"); return false;
  868. case 0x03: RaiseException("clock missing"); return false;
  869. }
  870. break;
  871. case 0x24:
  872. switch (Sub)
  873. { case 0x01: RaiseException("table missing"); return false; }
  874. break;
  875. case 0x25:
  876. switch (Sub)
  877. {
  878. case 0x02: RaiseException("memory error"); return false;
  879. case 0x03: RaiseException("I/O setting error"); return false;
  880. case 0x04: RaiseException("too many I/O points"); return false;
  881. case 0x05: RaiseException("CPU bus error"); return false;
  882. case 0x06: RaiseException("I/O duplication"); return false;
  883. case 0x07: RaiseException("CPU bus error"); return false;
  884. case 0x09: RaiseException("SYSMAC BUS/2 error"); return false;
  885. case 0x0a: RaiseException("CPU bus unit error"); return false;
  886. case 0x0d: RaiseException("SYSMAC BUS No. duplication"); return false;
  887. case 0x0f: RaiseException("memory error"); return false;
  888. case 0x10: RaiseException("SYSMAC BUS terminator missing"); return false;
  889. }
  890. break;
  891. case 0x26:
  892. switch (Sub)
  893. {
  894. case 0x01: RaiseException("no protection"); return false;
  895. case 0x02: RaiseException("incorrect password"); return false;
  896. case 0x04: RaiseException("protected"); return false;
  897. case 0x05: RaiseException("service already executing"); return false;
  898. case 0x06: RaiseException("service stopped"); return false;
  899. case 0x07: RaiseException("no execution right"); return false;
  900. case 0x08: RaiseException("settings required before execution"); return false;
  901. case 0x09: RaiseException("necessary items not set"); return false;
  902. case 0x0a: RaiseException("number already defined"); return false;
  903. case 0x0b: RaiseException("error will not clear"); return false;
  904. }
  905. break;
  906. case 0x30:
  907. switch (Sub)
  908. { case 0x01: RaiseException("no access right"); return false; }
  909. break;
  910. case 0x40:
  911. switch (Sub)
  912. { case 0x01: RaiseException("service aborted"); return false; }
  913. break;
  914. }
  915. //no hit
  916. RaiseException("unknown exception"); return false;
  917. }
  918. }
  919. }