MelsecMcNet.cs 34 KB

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