MelsecMcNet.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using MECF.Framework.RT.Core.IoProviders.Common;
  6. using MECF.Framework.RT.Core.IoProviders.Common.Net.NetworkBase;
  7. using MECF.Framework.RT.Core.IoProviders.Common.Transfer;
  8. namespace MECF.Framework.RT.Core.IoProviders.Melsec
  9. {
  10. /// <summary>
  11. /// 三菱PLC通讯类,采用Qna兼容3E帧协议实现,需要在PLC侧先的以太网模块先进行配置,必须为二进制通讯
  12. /// </summary>
  13. /// <remarks>
  14. /// 目前组件测试通过的PLC型号列表
  15. /// <list type="number">
  16. /// <item>Q06UDV PLC 感谢hwdq0012</item>
  17. /// <item>fx5u PLC 感谢山楂</item>
  18. /// <item>Q02CPU PLC </item>
  19. /// <item>L02CPU PLC </item>
  20. /// </list>
  21. /// 地址的输入的格式说明如下:
  22. /// <list type="table">
  23. /// <listheader>
  24. /// <term>地址名称</term>
  25. /// <term>地址代号</term>
  26. /// <term>示例</term>
  27. /// <term>地址进制</term>
  28. /// <term>字操作</term>
  29. /// <term>位操作</term>
  30. /// <term>备注</term>
  31. /// </listheader>
  32. /// <item>
  33. /// <term>内部继电器</term>
  34. /// <term>M</term>
  35. /// <term>M100,M200</term>
  36. /// <term>10</term>
  37. /// <term>√</term>
  38. /// <term>√</term>
  39. /// <term></term>
  40. /// </item>
  41. /// <item>
  42. /// <term>输入继电器</term>
  43. /// <term>X</term>
  44. /// <term>X100,X1A0</term>
  45. /// <term>16</term>
  46. /// <term>√</term>
  47. /// <term>√</term>
  48. /// <term></term>
  49. /// </item>
  50. /// <item>
  51. /// <term>输出继电器</term>
  52. /// <term>Y</term>
  53. /// <term>Y100,Y1A0</term>
  54. /// <term>16</term>
  55. /// <term>√</term>
  56. /// <term>√</term>
  57. /// <term></term>
  58. /// </item>
  59. /// <item>
  60. /// <term>锁存继电器</term>
  61. /// <term>L</term>
  62. /// <term>L100,L200</term>
  63. /// <term>10</term>
  64. /// <term>√</term>
  65. /// <term>√</term>
  66. /// <term></term>
  67. /// </item>
  68. /// <item>
  69. /// <term>报警器</term>
  70. /// <term>F</term>
  71. /// <term>F100,F200</term>
  72. /// <term>10</term>
  73. /// <term>√</term>
  74. /// <term>√</term>
  75. /// <term></term>
  76. /// </item>
  77. /// <item>
  78. /// <term>边沿继电器</term>
  79. /// <term>V</term>
  80. /// <term>V100,V200</term>
  81. /// <term>10</term>
  82. /// <term>√</term>
  83. /// <term>√</term>
  84. /// <term></term>
  85. /// </item>
  86. /// <item>
  87. /// <term>链接继电器</term>
  88. /// <term>B</term>
  89. /// <term>B100,B1A0</term>
  90. /// <term>16</term>
  91. /// <term>√</term>
  92. /// <term>√</term>
  93. /// <term></term>
  94. /// </item>
  95. /// <item>
  96. /// <term>步进继电器</term>
  97. /// <term>S</term>
  98. /// <term>S100,S200</term>
  99. /// <term>10</term>
  100. /// <term>√</term>
  101. /// <term>√</term>
  102. /// <term></term>
  103. /// </item>
  104. /// <item>
  105. /// <term>数据寄存器</term>
  106. /// <term>D</term>
  107. /// <term>D1000,D2000</term>
  108. /// <term>10</term>
  109. /// <term>√</term>
  110. /// <term>×</term>
  111. /// <term></term>
  112. /// </item>
  113. /// <item>
  114. /// <term>链接寄存器</term>
  115. /// <term>W</term>
  116. /// <term>W100,W1A0</term>
  117. /// <term>16</term>
  118. /// <term>√</term>
  119. /// <term>×</term>
  120. /// <term></term>
  121. /// </item>
  122. /// <item>
  123. /// <term>文件寄存器</term>
  124. /// <term>R</term>
  125. /// <term>R100,R200</term>
  126. /// <term>10</term>
  127. /// <term>√</term>
  128. /// <term>×</term>
  129. /// <term></term>
  130. /// </item>
  131. /// <item>
  132. /// <term>ZR文件寄存器</term>
  133. /// <term>ZR</term>
  134. /// <term>ZR100,ZR2A0</term>
  135. /// <term>16</term>
  136. /// <term>√</term>
  137. /// <term>×</term>
  138. /// <term></term>
  139. /// </item>
  140. /// <item>
  141. /// <term>变址寄存器</term>
  142. /// <term>Z</term>
  143. /// <term>Z100,Z200</term>
  144. /// <term>10</term>
  145. /// <term>√</term>
  146. /// <term>×</term>
  147. /// <term></term>
  148. /// </item>
  149. /// <item>
  150. /// <term>定时器的触点</term>
  151. /// <term>TS</term>
  152. /// <term>TS100,TS200</term>
  153. /// <term>10</term>
  154. /// <term>√</term>
  155. /// <term>√</term>
  156. /// <term></term>
  157. /// </item>
  158. /// <item>
  159. /// <term>定时器的线圈</term>
  160. /// <term>TC</term>
  161. /// <term>TC100,TC200</term>
  162. /// <term>10</term>
  163. /// <term>√</term>
  164. /// <term>√</term>
  165. /// <term></term>
  166. /// </item>
  167. /// <item>
  168. /// <term>定时器的当前值</term>
  169. /// <term>TN</term>
  170. /// <term>TN100,TN200</term>
  171. /// <term>10</term>
  172. /// <term>√</term>
  173. /// <term>×</term>
  174. /// <term></term>
  175. /// </item>
  176. /// <item>
  177. /// <term>累计定时器的触点</term>
  178. /// <term>SS</term>
  179. /// <term>SS100,SS200</term>
  180. /// <term>10</term>
  181. /// <term>√</term>
  182. /// <term>√</term>
  183. /// <term></term>
  184. /// </item>
  185. /// <item>
  186. /// <term>累计定时器的线圈</term>
  187. /// <term>SC</term>
  188. /// <term>SC100,SC200</term>
  189. /// <term>10</term>
  190. /// <term>√</term>
  191. /// <term>√</term>
  192. /// <term></term>
  193. /// </item>
  194. /// <item>
  195. /// <term>累计定时器的当前值</term>
  196. /// <term>SN</term>
  197. /// <term>SN100,SN200</term>
  198. /// <term>10</term>
  199. /// <term>√</term>
  200. /// <term>×</term>
  201. /// <term></term>
  202. /// </item>
  203. /// <item>
  204. /// <term>计数器的触点</term>
  205. /// <term>CS</term>
  206. /// <term>CS100,CS200</term>
  207. /// <term>10</term>
  208. /// <term>√</term>
  209. /// <term>√</term>
  210. /// <term></term>
  211. /// </item>
  212. /// <item>
  213. /// <term>计数器的线圈</term>
  214. /// <term>CC</term>
  215. /// <term>CC100,CC200</term>
  216. /// <term>10</term>
  217. /// <term>√</term>
  218. /// <term>√</term>
  219. /// <term></term>
  220. /// </item>
  221. /// <item>
  222. /// <term>计数器的当前值</term>
  223. /// <term>CN</term>
  224. /// <term>CN100,CN200</term>
  225. /// <term>10</term>
  226. /// <term>√</term>
  227. /// <term>×</term>
  228. /// <term></term>
  229. /// </item>
  230. /// </list>
  231. /// </remarks>
  232. /// <example>
  233. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="Usage" title="简单的短连接使用" />
  234. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="Usage2" title="简单的长连接使用" />
  235. /// </example>
  236. public class MelsecMcNet : NetworkDeviceBase<MelsecQnA3EBinaryMessage, RegularByteTransform>
  237. {
  238. #region Constructor
  239. /// <summary>
  240. /// 实例化三菱的Qna兼容3E帧协议的通讯对象
  241. /// </summary>
  242. public MelsecMcNet( )
  243. {
  244. WordLength = 1;
  245. }
  246. /// <summary>
  247. /// 实例化一个三菱的Qna兼容3E帧协议的通讯对象
  248. /// </summary>
  249. /// <param name="ipAddress">PLC的Ip地址</param>
  250. /// <param name="port">PLC的端口</param>
  251. public MelsecMcNet( string ipAddress, int port )
  252. {
  253. WordLength = 1;
  254. IpAddress = ipAddress;
  255. Port = port;
  256. }
  257. #endregion
  258. #region Public Member
  259. /// <summary>
  260. /// 网络号,通常为0
  261. /// </summary>
  262. /// <remarks>
  263. /// 依据PLC的配置而配置,如果PLC配置了1,那么此处也填0,如果PLC配置了2,此处就填2,测试不通的话,继续测试0
  264. /// </remarks>
  265. public byte NetworkNumber { get; set; } = 0x00;
  266. /// <summary>
  267. /// 网络站号,通常为0
  268. /// </summary>
  269. /// <remarks>
  270. /// 依据PLC的配置而配置,如果PLC配置了1,那么此处也填0,如果PLC配置了2,此处就填2,测试不通的话,继续测试0
  271. /// </remarks>
  272. public byte NetworkStationNumber { get; set; } = 0x00;
  273. #endregion
  274. #region Virtual Address Analysis
  275. /// <summary>
  276. /// 分析地址的方法,允许派生类里进行重写操作
  277. /// </summary>
  278. /// <param name="address">地址信息</param>
  279. /// <returns>解析后的数据信息</returns>
  280. protected virtual OperateResult<MelsecMcDataType, int> McAnalysisAddress( string address )
  281. {
  282. return MelsecHelper.McAnalysisAddress( address );
  283. }
  284. #endregion
  285. #region Read Write Support
  286. /// <summary>
  287. /// 从三菱PLC中读取想要的数据,输入地址,按照字单位读取,返回读取结果
  288. /// </summary>
  289. /// <param name="address">读取地址,格式为"M100","D100","W1A0"</param>
  290. /// <param name="length">读取的数据长度,字最大值960,位最大值7168</param>
  291. /// <returns>带成功标志的结果数据对象</returns>
  292. /// <remarks>
  293. /// 地址支持的列表参考 <seealso cref="MelsecMcNet"/> 的备注说明
  294. /// </remarks>
  295. /// <example>
  296. /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,读取如下:
  297. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample2" title="Read示例" />
  298. /// 以下是读取不同类型数据的示例
  299. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadExample1" title="Read示例" />
  300. /// </example>
  301. public override OperateResult<byte[]> Read( string address, ushort length )
  302. {
  303. // 分析地址
  304. OperateResult<byte[]> coreResult = MelsecHelper.BuildReadMcCoreCommand( address, length, false, McAnalysisAddress );
  305. if (!coreResult.IsSuccess) return coreResult;
  306. // 核心交互
  307. var read = ReadFromCoreServer( PackMcCommand( coreResult.Content, this.NetworkNumber, this.NetworkStationNumber ) );
  308. if (!read.IsSuccess) return OperateResult.CreateFailedResult<byte[]>( read );
  309. // 错误代码验证
  310. ushort errorCode = BitConverter.ToUInt16( read.Content, 9 );
  311. if (errorCode != 0) return new OperateResult<byte[]>( errorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  312. // 数据解析,需要传入是否使用位的参数
  313. return ExtractActualData( SoftBasic.BytesArrayRemoveBegin( read.Content, 11 ), false );
  314. }
  315. /// <summary>
  316. /// 向PLC写入数据,数据格式为原始的字节类型
  317. /// </summary>
  318. /// <param name="address">初始地址</param>
  319. /// <param name="value">原始的字节数据</param>
  320. /// <example>
  321. /// 假设起始地址为D100,D100存储了温度,100.6℃值为1006,D101存储了压力,1.23Mpa值为123,D102,D103存储了产量计数,写入如下:
  322. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="WriteExample2" title="Write示例" />
  323. /// 以下是写入不同类型数据的示例
  324. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="WriteExample1" title="Write示例" />
  325. /// </example>
  326. /// <returns>结果</returns>
  327. public override OperateResult Write( string address, byte[] value )
  328. {
  329. // 分析地址
  330. OperateResult<byte[]> coreResult = MelsecHelper.BuildWriteWordCoreCommand( address, value, McAnalysisAddress );
  331. if (!coreResult.IsSuccess) return coreResult;
  332. // 核心交互
  333. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( coreResult.Content, NetworkNumber, NetworkStationNumber ) );
  334. if (!read.IsSuccess) return read;
  335. // 错误码校验
  336. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  337. if (ErrorCode != 0) return new OperateResult<byte[]>( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  338. // 成功
  339. return OperateResult.CreateSuccessResult( );
  340. }
  341. #endregion
  342. #region Bool Operate Support
  343. /// <summary>
  344. /// 从三菱PLC中批量读取位软元件,返回读取结果
  345. /// </summary>
  346. /// <param name="address">起始地址</param>
  347. /// <param name="length">读取的长度</param>
  348. /// <returns>带成功标志的结果数据对象</returns>
  349. /// <remarks>
  350. /// 地址支持的列表参考 <seealso cref="MelsecMcNet"/> 的备注说明
  351. /// </remarks>
  352. /// <example>
  353. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="ReadBool" title="Bool类型示例" />
  354. /// </example>
  355. public OperateResult<bool[]> ReadBool( string address, ushort length )
  356. {
  357. // 获取指令
  358. OperateResult<byte[]> coreResult = MelsecHelper.BuildReadMcCoreCommand( address, length, true, McAnalysisAddress );
  359. if (!coreResult.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( coreResult );
  360. // 核心交互
  361. var read = ReadFromCoreServer( PackMcCommand( coreResult.Content, NetworkNumber, NetworkStationNumber ) );
  362. if (!read.IsSuccess) return OperateResult.CreateFailedResult<bool[]>(read);
  363. // 错误代码验证
  364. ushort errorCode = BitConverter.ToUInt16( read.Content, 9 );
  365. if (errorCode != 0) return new OperateResult<bool[]>( errorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  366. // 数据解析,需要传入是否使用位的参数
  367. var extract = ExtractActualData( SoftBasic.BytesArrayRemoveBegin( read.Content, 11 ), true );
  368. if(!extract.IsSuccess) return OperateResult.CreateFailedResult<bool[]>( extract );
  369. // 转化bool数组
  370. return OperateResult.CreateSuccessResult( extract.Content.Select( m => m == 0x01 ).Take( length ).ToArray( ) );
  371. }
  372. /// <summary>
  373. /// 从三菱PLC中批量读取位软元件,返回读取结果
  374. /// </summary>
  375. /// <param name="address">起始地址</param>
  376. /// <returns>带成功标志的结果数据对象</returns>
  377. /// <example>参照 <see cref="ReadBool(string, ushort)"/> 方法 </example>
  378. public OperateResult<bool> ReadBool( string address )
  379. {
  380. OperateResult<bool[]> read = ReadBool( address, 1 );
  381. if (!read.IsSuccess) return OperateResult.CreateFailedResult<bool>( read );
  382. return OperateResult.CreateSuccessResult<bool>( read.Content[0] );
  383. }
  384. /// <summary>
  385. /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100
  386. /// </summary>
  387. /// <param name="address">要写入的数据地址</param>
  388. /// <param name="value">要写入的实际数据,长度为8的倍数</param>
  389. /// <example>
  390. /// 详细请查看<see cref="Write(string, bool[])"/>方法的示例
  391. /// </example>
  392. /// <returns>返回写入结果</returns>
  393. public OperateResult Write( string address, bool value )
  394. {
  395. return Write( address, new bool[] { value} );
  396. }
  397. /// <summary>
  398. /// 向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100
  399. /// </summary>
  400. /// <param name="address">要写入的数据地址</param>
  401. /// <param name="values">要写入的实际数据,可以指定任意的长度</param>
  402. /// <example>
  403. /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\melsecTest.cs" region="WriteBool" title="Write示例" />
  404. /// </example>
  405. /// <returns>返回写入结果</returns>
  406. public OperateResult Write( string address, bool[] values )
  407. {
  408. OperateResult<byte[]> coreResult = MelsecHelper.BuildWriteBitCoreCommand( address, values, McAnalysisAddress );
  409. if (!coreResult.IsSuccess) return coreResult;
  410. // 核心交互
  411. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( coreResult.Content, NetworkNumber, NetworkStationNumber ) );
  412. if (!read.IsSuccess) return read;
  413. // 错误码校验
  414. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  415. if (ErrorCode != 0) return new OperateResult<byte[]>( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  416. // 成功
  417. return OperateResult.CreateSuccessResult( );
  418. }
  419. #endregion
  420. #region Remote Operate
  421. /// <summary>
  422. /// 远程Run操作
  423. /// </summary>
  424. /// <returns>是否成功</returns>
  425. public OperateResult RemoteRun( )
  426. {
  427. // 核心交互
  428. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( new byte[] { 0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }, NetworkNumber, NetworkStationNumber ) );
  429. if (!read.IsSuccess) return read;
  430. // 错误码校验
  431. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  432. if (ErrorCode != 0) return new OperateResult( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  433. // 成功
  434. return OperateResult.CreateSuccessResult( );
  435. }
  436. /// <summary>
  437. /// 远程Stop操作
  438. /// </summary>
  439. /// <returns>是否成功</returns>
  440. public OperateResult RemoteStop( )
  441. {
  442. // 核心交互
  443. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( new byte[] { 0x02, 0x10, 0x00, 0x00, 0x01, 0x00 }, NetworkNumber, NetworkStationNumber ) );
  444. if (!read.IsSuccess) return read;
  445. // 错误码校验
  446. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  447. if (ErrorCode != 0) return new OperateResult( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  448. // 成功
  449. return OperateResult.CreateSuccessResult( );
  450. }
  451. /// <summary>
  452. /// 远程Reset操作
  453. /// </summary>
  454. /// <returns>是否成功</returns>
  455. public OperateResult RemoteReset()
  456. {
  457. // 核心交互
  458. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( new byte[] { 0x06, 0x10, 0x00, 0x00, 0x01, 0x00 }, NetworkNumber, NetworkStationNumber ) );
  459. if (!read.IsSuccess) return read;
  460. // 错误码校验
  461. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  462. if (ErrorCode != 0) return new OperateResult( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  463. // 成功
  464. return OperateResult.CreateSuccessResult( );
  465. }
  466. /// <summary>
  467. /// 读取PLC的型号信息
  468. /// </summary>
  469. /// <returns>返回型号的结果对象</returns>
  470. public OperateResult<string> ReadPlcType( )
  471. {
  472. // 核心交互
  473. OperateResult<byte[]> read = ReadFromCoreServer( PackMcCommand( new byte[] { 0x01, 0x01, 0x00, 0x00 }, NetworkNumber, NetworkStationNumber ) );
  474. if (!read.IsSuccess) return OperateResult.CreateFailedResult<string>( read );
  475. // 错误码校验
  476. ushort ErrorCode = BitConverter.ToUInt16( read.Content, 9 );
  477. if (ErrorCode != 0) return new OperateResult<string>( ErrorCode, StringResources.Language.MelsecPleaseReferToManulDocument );
  478. // 成功
  479. return OperateResult.CreateSuccessResult( Encoding.ASCII.GetString( read.Content, 11, 16 ).TrimEnd( ) );
  480. }
  481. #endregion
  482. #region Object Override
  483. /// <summary>
  484. /// 获取当前对象的字符串标识形式
  485. /// </summary>
  486. /// <returns>字符串信息</returns>
  487. public override string ToString()
  488. {
  489. return $"MelsecMcNet[{IpAddress}:{Port}]";
  490. }
  491. #endregion
  492. #region Static Method Helper
  493. /// <summary>
  494. /// 将MC协议的核心报文打包成一个可以直接对PLC进行发送的原始报文
  495. /// </summary>
  496. /// <param name="mcCore">MC协议的核心报文</param>
  497. /// <param name="networkNumber">网络号</param>
  498. /// <param name="networkStationNumber">网络站号</param>
  499. /// <returns>原始报文信息</returns>
  500. public static byte[] PackMcCommand(byte[] mcCore, byte networkNumber = 0, byte networkStationNumber = 0)
  501. {
  502. byte[] _PLCCommand = new byte[11 + mcCore.Length];
  503. _PLCCommand[0] = 0x50; // 副标题
  504. _PLCCommand[1] = 0x00;
  505. _PLCCommand[2] = networkNumber; // 网络号
  506. _PLCCommand[3] = 0xFF; // PLC编号
  507. _PLCCommand[4] = 0xFF; // 目标模块IO编号
  508. _PLCCommand[5] = 0x03;
  509. _PLCCommand[6] = networkStationNumber; // 目标模块站号
  510. _PLCCommand[7] = (byte)((_PLCCommand.Length - 9) % 256); // 请求数据长度
  511. _PLCCommand[8] = (byte)((_PLCCommand.Length - 9) / 256);
  512. _PLCCommand[9] = 0x0A; // CPU监视定时器
  513. _PLCCommand[10] = 0x00;
  514. mcCore.CopyTo( _PLCCommand, 11 );
  515. return _PLCCommand;
  516. }
  517. /// <summary>
  518. /// 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取
  519. /// </summary>
  520. /// <param name="response">反馈的数据内容</param>
  521. /// <param name="isBit">是否位读取</param>
  522. /// <returns>解析后的结果对象</returns>
  523. public static OperateResult<byte[]> ExtractActualData( byte[] response, bool isBit )
  524. {
  525. if (isBit)
  526. {
  527. // 位读取
  528. byte[] Content = new byte[response.Length * 2];
  529. for (int i = 0; i < response.Length; i++)
  530. {
  531. if ((response[i] & 0x10) == 0x10)
  532. {
  533. Content[i * 2 + 0] = 0x01;
  534. }
  535. if ((response[i] & 0x01) == 0x01)
  536. {
  537. Content[i * 2 + 1] = 0x01;
  538. }
  539. }
  540. return OperateResult.CreateSuccessResult( Content );
  541. }
  542. else
  543. {
  544. // 字读取
  545. return OperateResult.CreateSuccessResult( response );
  546. }
  547. }
  548. #endregion
  549. }
  550. }