You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
13 KiB

8 months ago
  1. using Mirle.Component.MPLC.DataBlocks.DeviceRange.Interfaces;
  2. using Mirle.Component.MPLC.DataBlocks.Interfaces;
  3. using System;
  4. using System.Collections;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.IO.MemoryMappedFiles;
  8. using System.Threading;
  9. namespace Mirle.Component.MPLC.DataBlocks
  10. {
  11. /// <summary>
  12. /// 共享記憶體資料區塊
  13. /// </summary>
  14. public class SMDataBlock : IDataBlock, IDisposable
  15. {
  16. /// <summary>
  17. /// 建構式
  18. /// </summary>
  19. /// <param name="deviceRange">設備範圍介面</param>
  20. /// <param name="sharedMemoryName">共享記憶體名稱</param>
  21. public SMDataBlock(ITypeDeviceRange deviceRange, string sharedMemoryName)
  22. {
  23. DeviceRange = deviceRange;
  24. _mmfName = sharedMemoryName;
  25. Initial();
  26. }
  27. /// <summary>
  28. /// 原始資料物件鎖定
  29. /// </summary>
  30. protected readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
  31. /// <summary>
  32. /// 共享記憶體名稱
  33. /// </summary>
  34. protected string _mmfName;
  35. /// <summary>
  36. /// 共享記憶體長度
  37. /// </summary>
  38. protected long _mmfLength;
  39. /// <summary>
  40. /// 共享記憶體對應檔案
  41. /// </summary>
  42. protected MemoryMappedFile _mmf;
  43. /// <summary>
  44. /// 設備範圍介面
  45. /// </summary>
  46. public ITypeDeviceRange DeviceRange { get; }
  47. /// <summary>
  48. /// 共享記憶體對應名稱
  49. /// </summary>
  50. public string MemoryMappedName => _mmfName;
  51. /// <summary>
  52. /// 初始化
  53. /// </summary>
  54. protected virtual void Initial()
  55. {
  56. _mmfLength = DeviceRange.ByteArrayLength;
  57. #if NET5_0 || NET6_0
  58. if (OperatingSystem.IsWindows())
  59. {
  60. _mmf = MemoryMappedFile.CreateOrOpen(_mmfName, _mmfLength);
  61. }
  62. else
  63. {
  64. _mmf = MemoryMappedFile.CreateFromFile(_mmfName);
  65. }
  66. #elif NETFRAMEWORK
  67. _mmf = MemoryMappedFile.CreateOrOpen(_mmfName, _mmfLength);
  68. #else
  69. _mmf = MemoryMappedFile.CreateFromFile(_mmfName);
  70. #endif
  71. }
  72. /// <summary>
  73. /// 設置原始資料
  74. /// </summary>
  75. /// <param name="newRawData">原始資料</param>
  76. public virtual void SetRawData(byte[] newRawData)
  77. {
  78. try
  79. {
  80. _rwLock.EnterWriteLock();
  81. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  82. using BinaryWriter writer = new BinaryWriter(stream);
  83. stream.Seek(0, SeekOrigin.Begin);
  84. for (int i = 0; i < Math.Min(newRawData.Length, _mmfLength); i++)
  85. {
  86. writer.Write(newRawData[i]);
  87. }
  88. }
  89. catch (Exception ex)
  90. {
  91. Debug.WriteLine($"{ex}");
  92. }
  93. finally
  94. {
  95. _rwLock.ExitWriteLock();
  96. }
  97. }
  98. /// <summary>
  99. /// 取得原始資料
  100. /// </summary>
  101. /// <returns>原始資料</returns>
  102. public virtual byte[] GetRawData()
  103. {
  104. byte[] data = new byte[_mmfLength];
  105. try
  106. {
  107. _rwLock.EnterReadLock();
  108. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  109. using BinaryReader reader = new BinaryReader(stream);
  110. stream.Seek(0, SeekOrigin.Begin);
  111. for (int i = 0; i < _mmfLength; i++)
  112. {
  113. data[i] = reader.ReadByte();
  114. }
  115. }
  116. catch (Exception ex)
  117. {
  118. Debug.WriteLine($"{ex}");
  119. }
  120. finally
  121. {
  122. _rwLock.ExitReadLock();
  123. }
  124. return data;
  125. }
  126. /// <summary>
  127. /// 取得位元
  128. /// </summary>
  129. /// <param name="address">位置</param>
  130. /// <param name="value">是否成功取得</param>
  131. /// <returns>True/False</returns>
  132. public virtual bool TryGetBit(string address, out bool value)
  133. {
  134. value = false;
  135. try
  136. {
  137. _rwLock.EnterReadLock();
  138. if (DeviceRange.TryGetByteArrayOffset(address, out int offset) && DeviceRange.TryGetByteArrayBitIndex(address, out int index))
  139. {
  140. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  141. using BinaryReader reader = new BinaryReader(stream);
  142. stream.Seek(offset, SeekOrigin.Begin);
  143. ushort word = reader.ReadUInt16();
  144. BitArray bitArray = new BitArray(BitConverter.GetBytes(word));
  145. value = bitArray.Get(index);
  146. return true;
  147. }
  148. }
  149. catch (Exception ex)
  150. {
  151. Debug.WriteLine($"{ex}");
  152. }
  153. finally
  154. {
  155. _rwLock.ExitReadLock();
  156. }
  157. return false;
  158. }
  159. /// <summary>
  160. /// 設置位元開啟
  161. /// </summary>
  162. /// <param name="address">位置</param>
  163. /// <returns>True/False</returns>
  164. public bool TrySetBitOn(string address)
  165. {
  166. return SetBit(address, true);
  167. }
  168. /// <summary>
  169. /// 設置位元
  170. /// </summary>
  171. /// <param name="address">位置</param>
  172. /// <param name="isOn">是否開啟</param>
  173. /// <returns>True/False</returns>
  174. protected virtual bool SetBit(string address, bool isOn)
  175. {
  176. try
  177. {
  178. _rwLock.EnterWriteLock();
  179. if (DeviceRange.TryGetByteArrayOffset(address, out int offset) && DeviceRange.TryGetByteArrayBitIndex(address, out int index))
  180. {
  181. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  182. using BinaryReader reader = new BinaryReader(stream);
  183. stream.Seek(offset, SeekOrigin.Begin);
  184. ushort word = reader.ReadUInt16();
  185. BitArray bitArray = new BitArray(BitConverter.GetBytes(word));
  186. bitArray.Set(index, isOn);
  187. byte[] tmpBytes = new byte[2];
  188. bitArray.CopyTo(tmpBytes, 0);
  189. stream = _mmf.CreateViewStream();
  190. using BinaryWriter writer = new BinaryWriter(stream);
  191. stream.Seek(offset, SeekOrigin.Begin);
  192. writer.Write(tmpBytes[0]);
  193. writer.Write(tmpBytes[1]);
  194. return true;
  195. }
  196. }
  197. catch (Exception ex)
  198. {
  199. Debug.WriteLine($"{ex}");
  200. }
  201. finally
  202. {
  203. _rwLock.ExitWriteLock();
  204. }
  205. return false;
  206. }
  207. /// <summary>
  208. /// 設置位元關閉
  209. /// </summary>
  210. /// <param name="address">位置</param>
  211. /// <returns>True/False</returns>
  212. public bool TrySetBitOff(string address)
  213. {
  214. return SetBit(address, false);
  215. }
  216. /// <summary>
  217. /// 取得字元
  218. /// </summary>
  219. /// <param name="address">位置</param>
  220. /// <param name="value">值</param>
  221. /// <returns>True/False</returns>
  222. public virtual bool TryGetWord(string address, out int value)
  223. {
  224. value = 0;
  225. try
  226. {
  227. _rwLock.EnterReadLock();
  228. if (DeviceRange.TryGetByteArrayOffset(address, out int offset))
  229. {
  230. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  231. using BinaryReader reader = new BinaryReader(stream);
  232. stream.Seek(offset, SeekOrigin.Begin);
  233. value = reader.ReadUInt16();
  234. return true;
  235. }
  236. }
  237. catch (Exception ex)
  238. {
  239. Debug.WriteLine($"{ex}");
  240. }
  241. finally
  242. {
  243. _rwLock.ExitReadLock();
  244. }
  245. return false;
  246. }
  247. /// <summary>
  248. /// 設置字元
  249. /// </summary>
  250. /// <param name="address">位置</param>
  251. /// <param name="value">值</param>
  252. /// <returns>True/False</returns>
  253. public virtual bool TrySetWord(string address, int value)
  254. {
  255. try
  256. {
  257. _rwLock.EnterWriteLock();
  258. if (DeviceRange.TryGetByteArrayOffset(address, out int offset))
  259. {
  260. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  261. using BinaryWriter writer = new BinaryWriter(stream);
  262. stream.Seek(offset, SeekOrigin.Begin);
  263. byte[] tmpBytes = BitConverter.GetBytes(value);
  264. writer.Write(tmpBytes[0]);
  265. writer.Write(tmpBytes[1]);
  266. return true;
  267. }
  268. }
  269. catch (Exception ex)
  270. {
  271. Debug.WriteLine($"{ex}");
  272. }
  273. finally
  274. {
  275. _rwLock.ExitWriteLock();
  276. }
  277. return false;
  278. }
  279. /// <summary>
  280. /// 取得多個字元
  281. /// </summary>
  282. /// <param name="address">位置</param>
  283. /// <param name="data">資料集</param>
  284. /// <param name="length">長度</param>
  285. /// <returns>True/False</returns>
  286. public virtual bool TryGetWords(string address, out int[] data, int length)
  287. {
  288. data = new int[length];
  289. try
  290. {
  291. _rwLock.EnterReadLock();
  292. if (DeviceRange.TryGetByteArrayOffset(address, out int offset))
  293. {
  294. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  295. using BinaryReader reader = new BinaryReader(stream);
  296. stream.Seek(offset, SeekOrigin.Begin);
  297. for (int i = 0; i < length; i++)
  298. {
  299. data[i] = reader.ReadUInt16();
  300. }
  301. return true;
  302. }
  303. }
  304. catch (Exception ex)
  305. {
  306. Debug.WriteLine($"{ex}");
  307. }
  308. finally
  309. {
  310. _rwLock.ExitReadLock();
  311. }
  312. return false;
  313. }
  314. /// <summary>
  315. /// 取得多個字元
  316. /// </summary>
  317. /// <param name="address">位置</param>
  318. /// <param name="data">資料集</param>
  319. /// <returns>True/False</returns>
  320. public virtual bool TrySetWords(string address, int[] data)
  321. {
  322. try
  323. {
  324. _rwLock.EnterWriteLock();
  325. if (DeviceRange.TryGetByteArrayOffset(address, out int offset))
  326. {
  327. MemoryMappedViewStream stream = _mmf.CreateViewStream();
  328. using BinaryWriter writer = new BinaryWriter(stream);
  329. stream.Seek(offset, SeekOrigin.Begin);
  330. for (int i = 0; i < data.Length; i++)
  331. {
  332. byte[] tmpBytes = BitConverter.GetBytes(data[i]);
  333. writer.Write(tmpBytes[0]);
  334. writer.Write(tmpBytes[1]);
  335. }
  336. return true;
  337. }
  338. }
  339. catch (Exception ex)
  340. {
  341. Debug.WriteLine($"{ex}");
  342. }
  343. finally
  344. {
  345. _rwLock.ExitWriteLock();
  346. }
  347. return false;
  348. }
  349. #region IDisposable Support
  350. private bool disposedValue = false;
  351. /// <summary>
  352. /// 釋放資源
  353. /// </summary>
  354. /// <param name="disposing"></param>
  355. protected virtual void Dispose(bool disposing)
  356. {
  357. if (!disposedValue)
  358. {
  359. if (disposing)
  360. {
  361. _mmf?.Dispose();
  362. _rwLock?.Dispose();
  363. }
  364. disposedValue = true;
  365. }
  366. }
  367. /// <summary>
  368. /// 解構式
  369. /// </summary>
  370. ~SMDataBlock()
  371. {
  372. Dispose(false);
  373. }
  374. /// <summary>
  375. /// 釋放資源
  376. /// </summary>
  377. public void Dispose()
  378. {
  379. Dispose(true);
  380. GC.SuppressFinalize(this);
  381. }
  382. #endregion
  383. }
  384. }