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.

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