using Mirle.Component.MPLC.DataBlocks.DeviceRange.Interfaces; using Mirle.Component.MPLC.DataBlocks.Interfaces; using System; using System.Collections; using System.Diagnostics; using System.IO; using System.IO.MemoryMappedFiles; using System.Threading; namespace Mirle.Component.MPLC.DataBlocks { /// /// 共享記憶體資料區塊 /// public class SMDataBlock : IDataBlock, IDisposable { /// /// 建構式 /// /// 設備範圍介面 /// 共享記憶體名稱 public SMDataBlock(ITypeDeviceRange deviceRange, string sharedMemoryName) { DeviceRange = deviceRange; _mmfName = sharedMemoryName; Initial(); } /// /// 原始資料物件鎖定 /// protected readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); /// /// 共享記憶體名稱 /// protected string _mmfName; /// /// 共享記憶體長度 /// protected long _mmfLength; /// /// 共享記憶體對應檔案 /// protected MemoryMappedFile _mmf; /// /// 設備範圍介面 /// public ITypeDeviceRange DeviceRange { get; } /// /// 共享記憶體對應名稱 /// public string MemoryMappedName => _mmfName; /// /// 初始化 /// protected virtual void Initial() { _mmfLength = DeviceRange.ByteArrayLength; #if NET5_0 || NET6_0 if (OperatingSystem.IsWindows()) { _mmf = MemoryMappedFile.CreateOrOpen(_mmfName, _mmfLength); } else { _mmf = MemoryMappedFile.CreateFromFile(_mmfName); } #elif NETFRAMEWORK _mmf = MemoryMappedFile.CreateOrOpen(_mmfName, _mmfLength); #else _mmf = MemoryMappedFile.CreateFromFile(_mmfName); #endif } /// /// 設置原始資料 /// /// 原始資料 public virtual void SetRawData(byte[] newRawData) { try { _rwLock.EnterWriteLock(); MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryWriter writer = new BinaryWriter(stream); stream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < Math.Min(newRawData.Length, _mmfLength); i++) { writer.Write(newRawData[i]); } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitWriteLock(); } } /// /// 取得原始資料 /// /// 原始資料 public virtual byte[] GetRawData() { byte[] data = new byte[_mmfLength]; try { _rwLock.EnterReadLock(); MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryReader reader = new BinaryReader(stream); stream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < _mmfLength; i++) { data[i] = reader.ReadByte(); } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitReadLock(); } return data; } /// /// 取得位元 /// /// 位置 /// 是否成功取得 /// True/False public virtual bool TryGetBit(string address, out bool value) { value = false; try { _rwLock.EnterReadLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset) && DeviceRange.TryGetByteArrayBitIndex(address, out int index)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryReader reader = new BinaryReader(stream); stream.Seek(offset, SeekOrigin.Begin); ushort word = reader.ReadUInt16(); BitArray bitArray = new BitArray(BitConverter.GetBytes(word)); value = bitArray.Get(index); return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitReadLock(); } return false; } /// /// 設置位元開啟 /// /// 位置 /// True/False public bool TrySetBitOn(string address) { return SetBit(address, true); } /// /// 設置位元 /// /// 位置 /// 是否開啟 /// True/False protected virtual bool SetBit(string address, bool isOn) { try { _rwLock.EnterWriteLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset) && DeviceRange.TryGetByteArrayBitIndex(address, out int index)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryReader reader = new BinaryReader(stream); stream.Seek(offset, SeekOrigin.Begin); ushort word = reader.ReadUInt16(); BitArray bitArray = new BitArray(BitConverter.GetBytes(word)); bitArray.Set(index, isOn); byte[] tmpBytes = new byte[2]; bitArray.CopyTo(tmpBytes, 0); stream = _mmf.CreateViewStream(); using BinaryWriter writer = new BinaryWriter(stream); stream.Seek(offset, SeekOrigin.Begin); writer.Write(tmpBytes[0]); writer.Write(tmpBytes[1]); return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitWriteLock(); } return false; } /// /// 設置位元關閉 /// /// 位置 /// True/False public bool TrySetBitOff(string address) { return SetBit(address, false); } /// /// 取得字元 /// /// 位置 /// 值 /// True/False public virtual bool TryGetWord(string address, out int value) { value = 0; try { _rwLock.EnterReadLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryReader reader = new BinaryReader(stream); stream.Seek(offset, SeekOrigin.Begin); value = reader.ReadUInt16(); return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitReadLock(); } return false; } /// /// 設置字元 /// /// 位置 /// 值 /// True/False public virtual bool TrySetWord(string address, int value) { try { _rwLock.EnterWriteLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryWriter writer = new BinaryWriter(stream); stream.Seek(offset, SeekOrigin.Begin); byte[] tmpBytes = BitConverter.GetBytes(value); writer.Write(tmpBytes[0]); writer.Write(tmpBytes[1]); return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitWriteLock(); } return false; } /// /// 取得多個字元 /// /// 位置 /// 資料集 /// 長度 /// True/False public virtual bool TryGetWords(string address, out int[] data, int length) { data = new int[length]; try { _rwLock.EnterReadLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryReader reader = new BinaryReader(stream); stream.Seek(offset, SeekOrigin.Begin); for (int i = 0; i < length; i++) { data[i] = reader.ReadUInt16(); } return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitReadLock(); } return false; } /// /// 取得多個字元 /// /// 位置 /// 資料集 /// True/False public virtual bool TrySetWords(string address, int[] data) { try { _rwLock.EnterWriteLock(); if (DeviceRange.TryGetByteArrayOffset(address, out int offset)) { MemoryMappedViewStream stream = _mmf.CreateViewStream(); using BinaryWriter writer = new BinaryWriter(stream); stream.Seek(offset, SeekOrigin.Begin); for (int i = 0; i < data.Length; i++) { byte[] tmpBytes = BitConverter.GetBytes(data[i]); writer.Write(tmpBytes[0]); writer.Write(tmpBytes[1]); } return true; } } catch (Exception ex) { Debug.WriteLine($"{ex}"); } finally { _rwLock.ExitWriteLock(); } return false; } #region IDisposable Support private bool disposedValue = false; /// /// 釋放資源 /// /// protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _mmf?.Dispose(); _rwLock?.Dispose(); } disposedValue = true; } } /// /// 解構式 /// ~SMDataBlock() { Dispose(false); } /// /// 釋放資源 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }