OmronFinsNet.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using HslCommunication.Core.IMessage;
  6. using HslCommunication.Core.Net;
  7. using HslCommunication.Core;
  8. using System.Net.Sockets;
  9. using HslCommunication.BasicFramework;
  10. namespace HslCommunication.Profinet.Omron
  11. {
  12. /// <summary>
  13. /// 欧姆龙PLC通讯类,采用Fins-Tcp通信协议实现
  14. /// </summary>
  15. public class OmronFinsNet : NetworkDoubleBase<FinsMessage,ReverseWordTransform> , IReadWriteNet
  16. {
  17. #region Constructor
  18. /// <summary>
  19. /// 实例化三菱的Qna兼容3E帧协议的通讯对象
  20. /// </summary>
  21. public OmronFinsNet( )
  22. {
  23. }
  24. /// <summary>
  25. /// 实例化一个三菱的Qna兼容3E帧协议的通讯对象
  26. /// </summary>
  27. /// <param name="ipAddress">PLCd的Ip地址</param>
  28. /// <param name="port">PLC的端口</param>
  29. public OmronFinsNet( string ipAddress, int port )
  30. {
  31. IpAddress = ipAddress;
  32. Port = port;
  33. }
  34. #endregion
  35. #region Public Member
  36. /// <summary>
  37. /// 信息控制字段,默认0x80
  38. /// </summary>
  39. public byte ICF { get; set; } = 0x80;
  40. /// <summary>
  41. /// 系统使用的内部信息
  42. /// </summary>
  43. public byte RSV { get; private set; } = 0x00;
  44. /// <summary>
  45. /// 网络层信息,默认0x02,如果有八层消息,就设置为0x07
  46. /// </summary>
  47. public byte GCT { get; set; } = 0x02;
  48. /// <summary>
  49. /// PLC的网络号地址,默认0x00
  50. /// </summary>
  51. public byte DNA { get; set; } = 0x00;
  52. /// <summary>
  53. /// PLC的节点地址,默认0x13
  54. /// </summary>
  55. public byte DA1 { get; set; } = 0x13;
  56. /// <summary>
  57. /// PLC的单元号地址
  58. /// </summary>
  59. public byte DA2 { get; set; } = 0x00;
  60. /// <summary>
  61. /// 上位机的网络号地址
  62. /// </summary>
  63. public byte SNA { get; set; } = 0x00;
  64. private byte computerSA1 = 0x0B;
  65. /// <summary>
  66. /// 上位机的节点地址,默认0x0B
  67. /// </summary>
  68. public byte SA1
  69. {
  70. get { return computerSA1; }
  71. set
  72. {
  73. computerSA1 = value;
  74. handSingle[19] = value;
  75. }
  76. }
  77. /// <summary>
  78. /// 上位机的单元号地址
  79. /// </summary>
  80. public byte SA2 { get; set; }
  81. /// <summary>
  82. /// 设备的标识号
  83. /// </summary>
  84. public byte SID { get; set; } = 0x00;
  85. #endregion
  86. #region Address Analysis
  87. /// <summary>
  88. /// 解析数据地址,Omron手册第188页
  89. /// </summary>
  90. /// <param name="address">数据地址</param>
  91. /// <param name="isBit">是否是位地址</param>
  92. /// <returns></returns>
  93. private OperateResult<OmronFinsDataType,byte[]> AnalysisAddress( string address ,bool isBit)
  94. {
  95. var result = new OperateResult<OmronFinsDataType, byte[]>( );
  96. try
  97. {
  98. switch (address[0])
  99. {
  100. case 'D':
  101. case 'd':
  102. {
  103. // DM区数据
  104. result.Content1 = OmronFinsDataType.DM;
  105. break;
  106. }
  107. case 'C':
  108. case 'c':
  109. {
  110. // CIO区数据
  111. result.Content1 = OmronFinsDataType.CIO;
  112. break;
  113. }
  114. case 'W':
  115. case 'w':
  116. {
  117. // WR区
  118. result.Content1 = OmronFinsDataType.WR;
  119. break;
  120. }
  121. case 'H':
  122. case 'h':
  123. {
  124. // HR区
  125. result.Content1 = OmronFinsDataType.HR;
  126. break;
  127. }
  128. case 'A':
  129. case 'a':
  130. {
  131. // AR区
  132. result.Content1 = OmronFinsDataType.AR;
  133. break;
  134. }
  135. default: throw new Exception( "输入的类型不支持,请重新输入" );
  136. }
  137. if(isBit)
  138. {
  139. // 位操作
  140. string[] splits = address.Substring( 1 ).Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries );
  141. ushort addr = ushort.Parse( splits[0] );
  142. result.Content2 = new byte[3];
  143. result.Content2[0] = BitConverter.GetBytes( addr )[1];
  144. result.Content2[1] = BitConverter.GetBytes( addr )[0];
  145. if (splits.Length > 1)
  146. {
  147. result.Content2[2] = byte.Parse( splits[1] );
  148. if (result.Content2[2] > 15)
  149. {
  150. throw new Exception( "输入的位地址只能在0-15之间。" );
  151. }
  152. }
  153. }
  154. else
  155. {
  156. // 字操作
  157. ushort addr = ushort.Parse( address.Substring( 1 ) );
  158. result.Content2 = new byte[3];
  159. result.Content2[0] = BitConverter.GetBytes( addr )[1];
  160. result.Content2[1] = BitConverter.GetBytes( addr )[0];
  161. }
  162. }
  163. catch (Exception ex)
  164. {
  165. result.Message = "地址格式填写错误:" + ex.Message;
  166. return result;
  167. }
  168. result.IsSuccess = true;
  169. return result;
  170. }
  171. private OperateResult<byte[]> ResponseValidAnalysis(byte[] response,bool isRead)
  172. {
  173. // 数据有效性分析
  174. if (response.Length >= 16)
  175. {
  176. // 提取错误码
  177. byte[] buffer = new byte[4];
  178. buffer[0] = response[15];
  179. buffer[1] = response[14];
  180. buffer[2] = response[13];
  181. buffer[3] = response[12];
  182. int err = BitConverter.ToInt32( buffer, 0 );
  183. if (err > 0)
  184. {
  185. return new OperateResult<byte[]>( )
  186. {
  187. ErrorCode = err,
  188. Message = OmronInfo.GetStatusDescription( err ),
  189. };
  190. }
  191. if (response.Length >= 30)
  192. {
  193. err = response[28] * 256 + response[29];
  194. if (err > 0)
  195. {
  196. return new OperateResult<byte[]>( )
  197. {
  198. ErrorCode = err,
  199. Message = "结束码错误,为:" + err,
  200. };
  201. }
  202. if (!isRead)
  203. {
  204. // 写入操作
  205. return OperateResult.CreateSuccessResult( new byte[0] );
  206. }
  207. else
  208. {
  209. // 读取操作
  210. byte[] content = new byte[response.Length - 30];
  211. if (content.Length > 0)
  212. {
  213. Array.Copy( response, 30, content, 0, content.Length );
  214. }
  215. return OperateResult.CreateSuccessResult( content );
  216. }
  217. }
  218. }
  219. return new OperateResult<byte[]>( )
  220. {
  221. Message = "数据长度接收错误",
  222. };
  223. }
  224. #endregion
  225. #region Build Command
  226. /// <summary>
  227. /// 将普通的指令打包成完整的指令
  228. /// </summary>
  229. /// <param name="cmd"></param>
  230. /// <returns></returns>
  231. private byte[] PackCommand(byte[] cmd)
  232. {
  233. byte[] buffer = new byte[26 + cmd.Length];
  234. Array.Copy( handSingle, 0, buffer, 0, 4 );
  235. byte[] tmp = BitConverter.GetBytes( buffer.Length - 8 );
  236. Array.Reverse( tmp );
  237. tmp.CopyTo( buffer, 4 );
  238. buffer[11] = 0x02;
  239. buffer[16] = ICF;
  240. buffer[17] = RSV;
  241. buffer[18] = GCT;
  242. buffer[19] = DNA;
  243. buffer[20] = DA1;
  244. buffer[21] = DA2;
  245. buffer[22] = SNA;
  246. buffer[23] = SA1;
  247. buffer[24] = SA2;
  248. buffer[25] = SID;
  249. cmd.CopyTo( buffer, 26 );
  250. return buffer;
  251. }
  252. /// <summary>
  253. /// 根据类型地址长度确认需要读取的指令头
  254. /// </summary>
  255. /// <param name="address">起始地址</param>
  256. /// <param name="length">长度</param>
  257. /// <param name="isBit">是否是位读取</param>
  258. /// <returns>带有成功标志的指令数据</returns>
  259. private OperateResult<byte[]> BuildReadCommand( string address, ushort length ,bool isBit)
  260. {
  261. var result = new OperateResult<byte[]>( );
  262. var analysis = AnalysisAddress( address, isBit );
  263. if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( analysis );
  264. byte[] _PLCCommand = new byte[8];
  265. _PLCCommand[0] = 0x01; // 读取存储区数据
  266. _PLCCommand[1] = 0x01;
  267. if(isBit)
  268. {
  269. _PLCCommand[2] = analysis.Content1.BitCode;
  270. }
  271. else
  272. {
  273. _PLCCommand[2] = analysis.Content1.WordCode;
  274. }
  275. analysis.Content2.CopyTo( _PLCCommand, 3 );
  276. _PLCCommand[6] = (byte)(length / 256); // 长度
  277. _PLCCommand[7] = (byte)(length % 256);
  278. try
  279. {
  280. result.Content = PackCommand( _PLCCommand );
  281. result.IsSuccess = true;
  282. }
  283. catch(Exception ex)
  284. {
  285. LogNet?.WriteException( ToString( ), ex );
  286. result.Message = ex.Message;
  287. }
  288. return result;
  289. }
  290. /// <summary>
  291. /// 根据类型地址以及需要写入的数据来生成指令头
  292. /// </summary>
  293. /// <param name="address">起始地址</param>
  294. /// <param name="value"></param>
  295. /// <param name="isBit">是否是位操作</param>
  296. /// <returns></returns>
  297. private OperateResult<byte[]> BuildWriteCommand( string address, byte[] value, bool isBit )
  298. {
  299. var result = new OperateResult<byte[]>( );
  300. var analysis = AnalysisAddress( address, isBit );
  301. if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( analysis );
  302. byte[] _PLCCommand = new byte[8 + value.Length];
  303. _PLCCommand[0] = 0x01; // 读取存储区数据
  304. _PLCCommand[1] = 0x02;
  305. if (isBit)
  306. {
  307. _PLCCommand[2] = analysis.Content1.BitCode;
  308. }
  309. else
  310. {
  311. _PLCCommand[2] = analysis.Content1.WordCode;
  312. }
  313. analysis.Content2.CopyTo( _PLCCommand, 3 );
  314. if (isBit)
  315. {
  316. _PLCCommand[6] = (byte)(value.Length / 256); // 长度
  317. _PLCCommand[7] = (byte)(value.Length % 256);
  318. }
  319. else
  320. {
  321. _PLCCommand[6] = (byte)(value.Length / 2 / 256); // 长度
  322. _PLCCommand[7] = (byte)(value.Length / 2 % 256);
  323. }
  324. value.CopyTo( _PLCCommand, 8 );
  325. try
  326. {
  327. result.Content = PackCommand( _PLCCommand );
  328. result.IsSuccess = true;
  329. }
  330. catch (Exception ex)
  331. {
  332. LogNet?.WriteException( ToString( ), ex );
  333. result.Message = ex.Message;
  334. }
  335. return result;
  336. }
  337. #endregion
  338. #region Customer Support
  339. /// <summary>
  340. /// 读取自定义的数据类型,只要规定了写入和解析规则
  341. /// </summary>
  342. /// <typeparam name="T">类型名称</typeparam>
  343. /// <param name="address">起始地址</param>
  344. /// <returns></returns>
  345. public OperateResult<T> ReadCustomer<T>( string address ) where T : IDataTransfer, new()
  346. {
  347. OperateResult<T> result = new OperateResult<T>( );
  348. T Content = new T( );
  349. OperateResult<byte[]> read = Read( address, Content.ReadCount );
  350. if (read.IsSuccess)
  351. {
  352. Content.ParseSource( read.Content );
  353. result.Content = Content;
  354. result.IsSuccess = true;
  355. }
  356. else
  357. {
  358. result.ErrorCode = read.ErrorCode;
  359. result.Message = read.Message;
  360. }
  361. return result;
  362. }
  363. /// <summary>
  364. /// 写入自定义的数据类型到PLC去,只要规定了生成字节的方法即可
  365. /// </summary>
  366. /// <typeparam name="T">自定义类型</typeparam>
  367. /// <param name="address">起始地址</param>
  368. /// <param name="data">实例对象</param>
  369. /// <returns></returns>
  370. public OperateResult WriteCustomer<T>( string address, T data ) where T : IDataTransfer, new()
  371. {
  372. return Write( address, data.ToSource( ) );
  373. }
  374. #endregion
  375. #region Double Mode Override
  376. /// <summary>
  377. /// 在连接上欧姆龙PLC后,需要进行一步握手协议
  378. /// </summary>
  379. /// <param name="socket"></param>
  380. /// <returns></returns>
  381. protected override OperateResult InitilizationOnConnect( Socket socket )
  382. {
  383. // handSingle就是握手信号字节
  384. OperateResult<byte[], byte[]> read = ReadFromCoreServerBase( socket, handSingle );
  385. if (!read.IsSuccess) return read;
  386. // 检查返回的状态
  387. byte[] buffer = new byte[4];
  388. buffer[0] = read.Content2[7];
  389. buffer[1] = read.Content2[6];
  390. buffer[2] = read.Content2[5];
  391. buffer[3] = read.Content2[4];
  392. int status = BitConverter.ToInt32( buffer, 0 );
  393. if(status != 0)
  394. {
  395. return new OperateResult( )
  396. {
  397. ErrorCode = status,
  398. Message = "初始化失败,具体原因请根据错误码查找"
  399. };
  400. }
  401. // 提取PLC的节点地址
  402. if (read.Content2.Length >= 16)
  403. {
  404. DA1 = read.Content2[15];
  405. }
  406. return OperateResult.CreateSuccessResult( ) ;
  407. }
  408. #endregion
  409. #region Read Support
  410. /// <summary>
  411. /// 从欧姆龙PLC中读取想要的数据,返回读取结果,读取单位为字
  412. /// </summary>
  413. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  414. /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param>
  415. /// <returns>带成功标志的结果数据对象</returns>
  416. public OperateResult<byte[]> Read( string address, ushort length )
  417. {
  418. //获取指令
  419. var command = BuildReadCommand( address, length, false );
  420. if (!command.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( command );
  421. // 核心数据交互
  422. OperateResult<byte[]> read = ReadFromCoreServer( command.Content );
  423. if(!read.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( read );
  424. // 数据有效性分析
  425. OperateResult<byte[]> valid = ResponseValidAnalysis( read.Content, true );
  426. if(!valid.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( valid );
  427. // 读取到了正确的数据
  428. return OperateResult.CreateSuccessResult( valid.Content );
  429. }
  430. /// <summary>
  431. /// 从欧姆龙PLC中批量读取位软元件,返回读取结果
  432. /// </summary>
  433. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  434. /// <param name="length">读取的长度</param>
  435. /// <returns>带成功标志的结果数据对象</returns>
  436. public OperateResult<bool[]> ReadBool( string address, ushort length )
  437. {
  438. //获取指令
  439. var command = BuildReadCommand( address, length, true );
  440. if (!command.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( command );
  441. // 核心数据交互
  442. OperateResult<byte[]> read = ReadFromCoreServer( command.Content );
  443. if (!read.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( read );
  444. // 数据有效性分析
  445. OperateResult<byte[]> valid = ResponseValidAnalysis( read.Content, true );
  446. if (!valid.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( valid );
  447. // 返回正确的数据信息
  448. return OperateResult.CreateSuccessResult( valid.Content.Select( m => m != 0x00 ? true : false ).ToArray( ) );
  449. }
  450. /// <summary>
  451. /// 从欧姆龙PLC中批量读取位软元件,返回读取结果
  452. /// </summary>
  453. /// <param name="address">读取地址,格式为"D100.0","C100.15","W100.7","H100.4","A100.9"</param>
  454. /// <returns>带成功标志的结果数据对象</returns>
  455. public OperateResult<bool> ReadBool( string address )
  456. {
  457. OperateResult<bool[]> read = ReadBool( address, 1 );
  458. if (read.IsSuccess)
  459. {
  460. return OperateResult.CreateSuccessResult( read.Content[0] );
  461. }
  462. else
  463. {
  464. return OperateResult.CreateFailedResult<bool>( read );
  465. }
  466. }
  467. /// <summary>
  468. /// 读取欧姆龙PLC中字软元件指定地址的short数据
  469. /// </summary>
  470. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  471. /// <returns>带成功标志的结果数据对象</returns>
  472. public OperateResult<short> ReadInt16( string address )
  473. {
  474. return GetInt16ResultFromBytes( Read( address, 1 ) );
  475. }
  476. /// <summary>
  477. /// 读取欧姆龙PLC中字软元件指定地址的ushort数据
  478. /// </summary>
  479. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  480. /// <returns>带成功标志的结果数据对象</returns>
  481. public OperateResult<ushort> ReadUInt16( string address )
  482. {
  483. return GetUInt16ResultFromBytes( Read( address, 1 ) );
  484. }
  485. /// <summary>
  486. /// 读取欧姆龙PLC中字软元件指定地址的int数据
  487. /// </summary>
  488. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  489. /// <returns>带成功标志的结果数据对象</returns>
  490. public OperateResult<int> ReadInt32( string address )
  491. {
  492. return GetInt32ResultFromBytes( Read( address, 2 ) );
  493. }
  494. /// <summary>
  495. /// 读取欧姆龙PLC中字软元件指定地址的uint数据
  496. /// </summary>
  497. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  498. /// <returns>带成功标志的结果数据对象</returns>
  499. public OperateResult<uint> ReadUInt32( string address )
  500. {
  501. return GetUInt32ResultFromBytes( Read( address, 2 ) );
  502. }
  503. /// <summary>
  504. /// 读取欧姆龙PLC中字软元件指定地址的float数据
  505. /// </summary>
  506. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  507. /// <returns>带成功标志的结果数据对象</returns>
  508. public OperateResult<float> ReadFloat( string address )
  509. {
  510. return GetSingleResultFromBytes( Read( address, 2 ) );
  511. }
  512. /// <summary>
  513. /// 读取欧姆龙PLC中字软元件指定地址的long数据
  514. /// </summary>
  515. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  516. /// <returns>带成功标志的结果数据对象</returns>
  517. public OperateResult<long> ReadInt64( string address )
  518. {
  519. return GetInt64ResultFromBytes( Read( address, 4 ) );
  520. }
  521. /// <summary>
  522. /// 读取欧姆龙PLC中字软元件指定地址的ulong数据
  523. /// </summary>
  524. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  525. /// <returns>带成功标志的结果数据对象</returns>
  526. public OperateResult<ulong> ReadUInt64( string address )
  527. {
  528. return GetUInt64ResultFromBytes( Read( address, 4 ) );
  529. }
  530. /// <summary>
  531. /// 读取欧姆龙PLC中字软元件指定地址的double数据
  532. /// </summary>
  533. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  534. /// <returns>带成功标志的结果数据对象</returns>
  535. public OperateResult<double> ReadDouble( string address )
  536. {
  537. return GetDoubleResultFromBytes( Read( address, 4 ) );
  538. }
  539. /// <summary>
  540. /// 读取欧姆龙PLC中字软元件地址地址的String数据,编码为ASCII
  541. /// </summary>
  542. /// <param name="address">读取地址,格式为"D100","C100","W100","H100","A100"</param>
  543. /// <param name="length">字符串长度</param>
  544. /// <returns>带成功标志的结果数据对象</returns>
  545. public OperateResult<string> ReadString( string address, ushort length )
  546. {
  547. return GetStringResultFromBytes( Read( address, length ) );
  548. }
  549. #endregion
  550. #region Write Base
  551. /// <summary>
  552. /// 向PLC写入数据,数据格式为原始的字节类型
  553. /// </summary>
  554. /// <param name="address">初始地址</param>
  555. /// <param name="value">原始的字节数据</param>
  556. /// <returns>结果</returns>
  557. public OperateResult Write( string address, byte[] value )
  558. {
  559. //获取指令
  560. var command = BuildWriteCommand( address, value, false );
  561. if (!command.IsSuccess) return command;
  562. // 核心数据交互
  563. OperateResult<byte[]> read = ReadFromCoreServer( command.Content );
  564. if (!read.IsSuccess) return read;
  565. // 数据有效性分析
  566. OperateResult<byte[]> valid = ResponseValidAnalysis( read.Content, false );
  567. if (!valid.IsSuccess) return valid;
  568. // 成功
  569. return OperateResult.CreateSuccessResult( ) ;
  570. }
  571. #endregion
  572. #region Write String
  573. /// <summary>
  574. /// 向PLC中字软元件写入字符串,编码格式为ASCII
  575. /// </summary>
  576. /// <param name="address">要写入的数据地址</param>
  577. /// <param name="value">要写入的实际数据</param>
  578. /// <returns>返回读取结果</returns>
  579. public OperateResult Write( string address, string value )
  580. {
  581. byte[] temp = Encoding.ASCII.GetBytes( value );
  582. temp = SoftBasic.ArrayExpandToLengthEven( temp );
  583. return Write( address, temp );
  584. }
  585. /// <summary>
  586. /// 向PLC中字软元件写入指定长度的字符串,超出截断,不够补0,编码格式为ASCII
  587. /// </summary>
  588. /// <param name="address">要写入的数据地址</param>
  589. /// <param name="value">要写入的实际数据</param>
  590. /// <param name="length">指定的字符串长度,必须大于0</param>
  591. /// <returns>返回读取结果</returns>
  592. public OperateResult Write( string address, string value, int length )
  593. {
  594. byte[] temp = Encoding.ASCII.GetBytes( value );
  595. temp = SoftBasic.ArrayExpandToLength( temp, length );
  596. temp = SoftBasic.ArrayExpandToLengthEven( temp );
  597. return Write( address, temp );
  598. }
  599. /// <summary>
  600. /// 向PLC中字软元件写入字符串,编码格式为Unicode
  601. /// </summary>
  602. /// <param name="address">要写入的数据地址</param>
  603. /// <param name="value">要写入的实际数据</param>
  604. /// <returns>返回读取结果</returns>
  605. public OperateResult WriteUnicodeString( string address, string value )
  606. {
  607. byte[] temp = Encoding.Unicode.GetBytes( value );
  608. return Write( address, temp );
  609. }
  610. /// <summary>
  611. /// 向PLC中字软元件写入指定长度的字符串,超出截断,不够补0,编码格式为Unicode
  612. /// </summary>
  613. /// <param name="address">要写入的数据地址</param>
  614. /// <param name="value">要写入的实际数据</param>
  615. /// <param name="length">指定的字符串长度,必须大于0</param>
  616. /// <returns>返回读取结果</returns>
  617. public OperateResult WriteUnicodeString( string address, string value, int length )
  618. {
  619. byte[] temp = Encoding.Unicode.GetBytes( value );
  620. temp = SoftBasic.ArrayExpandToLength( temp, length * 2 );
  621. return Write( address, temp );
  622. }
  623. #endregion
  624. #region Write bool[]
  625. /// <summary>
  626. /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0
  627. /// </summary>
  628. /// <param name="address">要写入的数据地址</param>
  629. /// <param name="value">要写入的实际数据,长度为8的倍数</param>
  630. /// <returns>返回写入结果</returns>
  631. public OperateResult Write( string address, bool value )
  632. {
  633. return Write( address, new bool[] { value } );
  634. }
  635. /// <summary>
  636. /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0
  637. /// </summary>
  638. /// <param name="address">要写入的数据地址</param>
  639. /// <param name="values">要写入的实际数据,可以指定任意的长度</param>
  640. /// <returns>返回写入结果</returns>
  641. public OperateResult Write( string address, bool[] values )
  642. {
  643. OperateResult result = new OperateResult( );
  644. //获取指令
  645. var command = BuildWriteCommand( address, values.Select( m => m ? (byte)0x01 : (byte)0x00 ).ToArray( ), true );
  646. if (!command.IsSuccess) return command;
  647. // 核心数据交互
  648. OperateResult<byte[]> read = ReadFromCoreServer( command.Content );
  649. if (!read.IsSuccess) return read;
  650. // 数据有效性分析
  651. OperateResult<byte[]> valid = ResponseValidAnalysis( read.Content, false );
  652. if (!valid.IsSuccess) return valid;
  653. // 写入成功
  654. return OperateResult.CreateSuccessResult( );
  655. }
  656. #endregion
  657. #region Write Short
  658. /// <summary>
  659. /// 向PLC中字软元件写入short数组,返回值说明
  660. /// </summary>
  661. /// <param name="address">要写入的数据地址</param>
  662. /// <param name="values">要写入的实际数据</param>
  663. /// <returns>返回写入结果</returns>
  664. public OperateResult Write( string address, short[] values )
  665. {
  666. return Write( address, ByteTransform.TransByte( values ) );
  667. }
  668. /// <summary>
  669. /// 向PLC中字软元件写入short数据,返回值说明
  670. /// </summary>
  671. /// <param name="address">要写入的数据地址</param>
  672. /// <param name="value">要写入的实际数据</param>
  673. /// <returns>返回写入结果</returns>
  674. public OperateResult Write( string address, short value )
  675. {
  676. return Write( address, new short[] { value } );
  677. }
  678. #endregion
  679. #region Write UShort
  680. /// <summary>
  681. /// 向PLC中字软元件写入ushort数组,返回值说明
  682. /// </summary>
  683. /// <param name="address">要写入的数据地址</param>
  684. /// <param name="values">要写入的实际数据</param>
  685. /// <returns>返回写入结果</returns>
  686. public OperateResult Write( string address, ushort[] values )
  687. {
  688. return Write( address, ByteTransform.TransByte( values ) );
  689. }
  690. /// <summary>
  691. /// 向PLC中字软元件写入ushort数据,返回值说明
  692. /// </summary>
  693. /// <param name="address">要写入的数据地址</param>
  694. /// <param name="value">要写入的实际数据</param>
  695. /// <returns>返回写入结果</returns>
  696. public OperateResult Write( string address, ushort value )
  697. {
  698. return Write( address, new ushort[] { value } );
  699. }
  700. #endregion
  701. #region Write Int
  702. /// <summary>
  703. /// 向PLC中字软元件写入int数组,返回值说明
  704. /// </summary>
  705. /// <param name="address">要写入的数据地址</param>
  706. /// <param name="values">要写入的实际数据</param>
  707. /// <returns>返回写入结果</returns>
  708. public OperateResult Write( string address, int[] values )
  709. {
  710. return Write( address, ByteTransform.TransByte( values ) );
  711. }
  712. /// <summary>
  713. /// 向PLC中字软元件写入int数据,返回值说明
  714. /// </summary>
  715. /// <param name="address">要写入的数据地址</param>
  716. /// <param name="value">要写入的实际数据</param>
  717. /// <returns>返回写入结果</returns>
  718. public OperateResult Write( string address, int value )
  719. {
  720. return Write( address, new int[] { value } );
  721. }
  722. #endregion
  723. #region Write UInt
  724. /// <summary>
  725. /// 向PLC中字软元件写入uint数组,返回值说明
  726. /// </summary>
  727. /// <param name="address">要写入的数据地址</param>
  728. /// <param name="values">要写入的实际数据</param>
  729. /// <returns>返回写入结果</returns>
  730. public OperateResult Write( string address, uint[] values )
  731. {
  732. return Write( address, ByteTransform.TransByte( values ) );
  733. }
  734. /// <summary>
  735. /// 向PLC中字软元件写入uint数据,返回值说明
  736. /// </summary>
  737. /// <param name="address">要写入的数据地址</param>
  738. /// <param name="value">要写入的实际数据</param>
  739. /// <returns>返回写入结果</returns>
  740. public OperateResult Write( string address, uint value )
  741. {
  742. return Write( address, new uint[] { value } );
  743. }
  744. #endregion
  745. #region Write Float
  746. /// <summary>
  747. /// 向PLC中字软元件写入float数组,返回值说明
  748. /// </summary>
  749. /// <param name="address">要写入的数据地址</param>
  750. /// <param name="values">要写入的实际数据</param>
  751. /// <returns>返回写入结果</returns>
  752. public OperateResult Write( string address, float[] values )
  753. {
  754. return Write( address, ByteTransform.TransByte( values ) );
  755. }
  756. /// <summary>
  757. /// 向PLC中字软元件写入float数据,返回值说明
  758. /// </summary>
  759. /// <param name="address">要写入的数据地址</param>
  760. /// <param name="value">要写入的实际数据</param>
  761. /// <returns>返回写入结果</returns>
  762. public OperateResult Write( string address, float value )
  763. {
  764. return Write( address, new float[] { value } );
  765. }
  766. #endregion
  767. #region Write Long
  768. /// <summary>
  769. /// 向PLC中字软元件写入long数组,返回值说明
  770. /// </summary>
  771. /// <param name="address">要写入的数据地址</param>
  772. /// <param name="values">要写入的实际数据</param>
  773. /// <returns>返回写入结果</returns>
  774. public OperateResult Write( string address, long[] values )
  775. {
  776. return Write( address, ByteTransform.TransByte( values ) );
  777. }
  778. /// <summary>
  779. /// 向PLC中字软元件写入long数据,返回值说明
  780. /// </summary>
  781. /// <param name="address">要写入的数据地址</param>
  782. /// <param name="value">要写入的实际数据</param>
  783. /// <returns>返回写入结果</returns>
  784. public OperateResult Write( string address, long value )
  785. {
  786. return Write( address, new long[] { value } );
  787. }
  788. #endregion
  789. #region Write ULong
  790. /// <summary>
  791. /// 向PLC中字软元件写入ulong数组,返回值说明
  792. /// </summary>
  793. /// <param name="address">要写入的数据地址</param>
  794. /// <param name="values">要写入的实际数据</param>
  795. /// <returns>返回写入结果</returns>
  796. public OperateResult Write( string address, ulong[] values )
  797. {
  798. return Write( address, ByteTransform.TransByte( values ) );
  799. }
  800. /// <summary>
  801. /// 向PLC中字软元件写入ulong数据,返回值说明
  802. /// </summary>
  803. /// <param name="address">要写入的数据地址</param>
  804. /// <param name="value">要写入的实际数据</param>
  805. /// <returns>返回写入结果</returns>
  806. public OperateResult Write( string address, ulong value )
  807. {
  808. return Write( address, new ulong[] { value } );
  809. }
  810. #endregion
  811. #region Write Double
  812. /// <summary>
  813. /// 向PLC中字软元件写入double数组,返回值说明
  814. /// </summary>
  815. /// <param name="address">要写入的数据地址</param>
  816. /// <param name="values">要写入的实际数据</param>
  817. /// <returns>返回写入结果</returns>
  818. public OperateResult Write( string address, double[] values )
  819. {
  820. return Write( address, ByteTransform.TransByte( values ) );
  821. }
  822. /// <summary>
  823. /// 向PLC中字软元件写入double数据,返回值说明
  824. /// </summary>
  825. /// <param name="address">要写入的数据地址</param>
  826. /// <param name="value">要写入的实际数据</param>
  827. /// <returns>返回写入结果</returns>
  828. public OperateResult Write( string address, double value )
  829. {
  830. return Write( address, new double[] { value } );
  831. }
  832. #endregion
  833. #region Hand Single
  834. // 握手信号
  835. // 46494E530000000C0000000000000000000000D6
  836. private byte[] handSingle = new byte[]
  837. {
  838. 0x46,0x49,0x4E,0x53, // FINS
  839. 0x00,0x00,0x00,0x0C, // 后面的命令长度
  840. 0x00,0x00,0x00,0x00, // 命令码
  841. 0x00,0x00,0x00,0x00, // 错误码
  842. 0x00,0x00,0x00,0x01 // 节点号
  843. };
  844. #endregion
  845. #region Object Override
  846. /// <summary>
  847. /// 获取当前对象的字符串标识形式
  848. /// </summary>
  849. /// <returns>字符串信息</returns>
  850. public override string ToString( )
  851. {
  852. return "OmronFinsNet";
  853. }
  854. #endregion
  855. }
  856. }