MelsecMcAsciiNet.cs 39 KB

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