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
}
}