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
391 lines
13 KiB
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
|
|
{
|
|
/// <summary>
|
|
/// 共享記憶體資料區塊
|
|
/// </summary>
|
|
public class SMDataBlock : IDataBlock, IDisposable
|
|
{
|
|
/// <summary>
|
|
/// 建構式
|
|
/// </summary>
|
|
/// <param name="deviceRange">設備範圍介面</param>
|
|
/// <param name="sharedMemoryName">共享記憶體名稱</param>
|
|
public SMDataBlock(ITypeDeviceRange deviceRange, string sharedMemoryName)
|
|
{
|
|
DeviceRange = deviceRange;
|
|
_mmfName = sharedMemoryName;
|
|
Initial();
|
|
}
|
|
/// <summary>
|
|
/// 原始資料物件鎖定
|
|
/// </summary>
|
|
protected readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
|
|
/// <summary>
|
|
/// 共享記憶體名稱
|
|
/// </summary>
|
|
protected string _mmfName;
|
|
/// <summary>
|
|
/// 共享記憶體長度
|
|
/// </summary>
|
|
protected long _mmfLength;
|
|
/// <summary>
|
|
/// 共享記憶體對應檔案
|
|
/// </summary>
|
|
protected MemoryMappedFile _mmf;
|
|
/// <summary>
|
|
/// 設備範圍介面
|
|
/// </summary>
|
|
public ITypeDeviceRange DeviceRange { get; }
|
|
/// <summary>
|
|
/// 共享記憶體對應名稱
|
|
/// </summary>
|
|
public string MemoryMappedName => _mmfName;
|
|
/// <summary>
|
|
/// 初始化
|
|
/// </summary>
|
|
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
|
|
}
|
|
/// <summary>
|
|
/// 設置原始資料
|
|
/// </summary>
|
|
/// <param name="newRawData">原始資料</param>
|
|
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();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 取得原始資料
|
|
/// </summary>
|
|
/// <returns>原始資料</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 取得位元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="value">是否成功取得</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 設置位元開啟
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <returns>True/False</returns>
|
|
public bool TrySetBitOn(string address)
|
|
{
|
|
return SetBit(address, true);
|
|
}
|
|
/// <summary>
|
|
/// 設置位元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="isOn">是否開啟</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 設置位元關閉
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <returns>True/False</returns>
|
|
public bool TrySetBitOff(string address)
|
|
{
|
|
return SetBit(address, false);
|
|
}
|
|
/// <summary>
|
|
/// 取得字元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="value">值</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 設置字元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="value">值</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 取得多個字元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="data">資料集</param>
|
|
/// <param name="length">長度</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 取得多個字元
|
|
/// </summary>
|
|
/// <param name="address">位置</param>
|
|
/// <param name="data">資料集</param>
|
|
/// <returns>True/False</returns>
|
|
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;
|
|
/// <summary>
|
|
/// 釋放資源
|
|
/// </summary>
|
|
/// <param name="disposing"></param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_mmf?.Dispose();
|
|
_rwLock?.Dispose();
|
|
}
|
|
disposedValue = true;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 解構式
|
|
/// </summary>
|
|
~SMDataBlock()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
/// <summary>
|
|
/// 釋放資源
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|