FinsPlc.cs 42 KB

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