FinsPlc.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  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. 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.Write(ex, String.Format("Communication failed with PLC {0}:{1}", _ip, _port));
  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.Write(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.Error(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.Error(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.Error(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.Error(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.Write(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. //public class Converter
  920. //{
  921. // public static byte[] StructToBytes(object obj)
  922. // {
  923. // int rawsize = Marshal.SizeOf(obj);
  924. // IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  925. // Marshal.StructureToPtr(obj, buffer, false);
  926. // byte[] rawdatas = new byte[rawsize];
  927. // Marshal.Copy(buffer, rawdatas, 0, rawsize);
  928. // Marshal.FreeHGlobal(buffer);
  929. // return rawdatas;
  930. // }
  931. // public static object BytesToStruct(byte[] buf, int len, Type type)
  932. // {
  933. // object rtn;
  934. // IntPtr buffer = Marshal.AllocHGlobal(len);
  935. // Marshal.Copy(buf, 0, buffer, len);
  936. // rtn = Marshal.PtrToStructure(buffer, type);
  937. // Marshal.FreeHGlobal(buffer);
  938. // return rtn;
  939. // }
  940. // public static void BytesToStruct(byte[] buf, int len, object rtn)
  941. // {
  942. // IntPtr buffer = Marshal.AllocHGlobal(len);
  943. // Marshal.Copy(buf, 0, buffer, len);
  944. // Marshal.PtrToStructure(buffer, rtn);
  945. // Marshal.FreeHGlobal(buffer);
  946. // }
  947. // public static void BytesToStruct(byte[] buf, object rtn)
  948. // {
  949. // BytesToStruct(buf, buf.Length, rtn);
  950. // }
  951. // public static object BytesToStruct(byte[] buf, Type type)
  952. // {
  953. // return BytesToStruct(buf, buf.Length, type);
  954. // }
  955. //}
  956. }