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.

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