Files
2025-11-25 20:14:41 +09:00

575 lines
21 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace AR.MemoryMap
{
public abstract class Core
{
protected ManualResetEvent mre;
protected MemoryMappedFile mmf;
protected Mutex mutex;
protected bool mutexCreated;
protected Func<bool> StartAction;
protected Func<bool> StopAction;
string MapFileName = string.Empty;
public int WriteTime = 100;
public int ReadTime = 100;
int MapSize = 100;
public bool Init { get; set; } = false;
Task loop;
protected bool brun = false;
public int LoopDelay { get; set; }
public string ErrorMessage { get; set; }
public Core(string mapFileName, int mapSize, int loopDelay = 50)
{
LoopDelay = loopDelay;
this.MapFileName = mapFileName;
this.MapSize = mapSize;
this.monitorvalue = new byte[mapSize];
mre = new ManualResetEvent(false);
}
~Core()
{
brun = false;
}
public bool Start()
{
Init = StartAction.Invoke();
return Init;
}
public void StartMonitor()
{
if (Init == false) return;
if (IsMonitorRun) return;
brun = true;
loop = Task.Factory.StartNew(() =>
{
Monitor_Loop();
});
}
public void StopMonitor()
{
brun = false;
}
public bool IsMonitorRun
{
get
{
if (loop == null) return false;
if (loop.IsCompleted) return false;
if (loop.IsCanceled) return false;
return true;
}
}
public bool SetMonitorTarget(bool All)
{
if (mre.WaitOne(100) == false) return false;
mre.Set();
return true;
}
byte[] monitorvalue;
public void Stop()
{
StopAction.Invoke();
}
private void Monitor_Loop()
{
while (brun)
{
//작업가능확인
bool readok = false;
byte[] value = null;
try
{
if (mre.WaitOne(100))
{
try
{
//메모리접근 권한 확인
if (MutexWaitOne(100))
{
//값을 읽은 경우
if (ReadBytes(0, this.MapSize, out value))
{
readok = true;
}
}
}
finally { mutex.ReleaseMutex(); }
}
}
finally { mre.Set(); }
if (readok)
{
//값의 변화가 있다면 이벤트 발생
List<int> changeindex = new List<int>();
for (int i = 0; i < value.Length; i++)
{
if (value[i] != monitorvalue[i]) changeindex.Add(i);
}
if (changeindex.Any())
{
ValueChanged.Invoke(this, new monitorvalueargs(changeindex.ToArray(), monitorvalue, value));
}
//신규값을 업데이트
Array.Copy(value, monitorvalue, value.Length);
}
//write
System.Threading.Thread.Sleep(LoopDelay);
}
}
public bool MutexWaitOne(int milli)
{
var MapFileSync = $"{MapFileName}{MapSize}";
if (mutexCreated == false)
{
mutex = new Mutex(false, MapFileSync, out mutexCreated);
return mutex.WaitOne(milli);
}
else
{
//이미생성된 경우에는 에러처리를 해야한다
try
{
return mutex.WaitOne(milli);
}
catch
{
//오류가있으니 다시 작성한다
mutex = new Mutex(false, MapFileSync, out mutexCreated);
return false;
}
}
}
public event EventHandler<monitorvalueargs> ValueChanged;
public class monitorvalueargs : EventArgs
{
public byte[] newdata;
public byte[] olddata;
public int[] idxlist;
public monitorvalueargs(int[] idxs, byte[] beforedata, byte[] afterdata)
{
idxlist = new int[idxs.Length];
Array.Copy(idxs, this.idxlist, idxs.Length);
newdata = new byte[afterdata.Length];
Array.Copy(afterdata, newdata, afterdata.Length);
olddata = new byte[beforedata.Length];
Array.Copy(beforedata, olddata, beforedata.Length);
}
}
#region "WRITE"
public bool Write(int address, Boolean value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(value.GetType());
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, byte[] value, int startIndex = 0, int size = 0)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
if (size == 0) size = Marshal.SizeOf(value.GetType());
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value,startIndex,size);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, byte value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(value.GetType());
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, string value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, Int32 value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, Int16 value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, UInt32 value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, UInt16 value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, Single value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
public bool Write(int address, Double value)
{
if (Init == false) return false;
if (MutexWaitOne(WriteTime) == false) return false;
Type type = value.GetType();
var size = Marshal.SizeOf(type);
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
using (var writer = new BinaryWriter(stream))
writer.Write(value);
mutex.ReleaseMutex();
return true;
}
//public bool Write<T>(int address, T value)
//{
// if (checktype(value.GetType()) == false) return false;
// if (MutexWaitOne(3000) == false) return false;
// var size = Marshal.SizeOf(typeof(T));
// using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
// {
// using (var reader = new BinaryWriter(stream))
// {
// var a = (byte[])Convert.ChangeType(value, typeof(byte[]));
// reader.Write(a, 0, a.Length);
// }
// }
// mutex.ReleaseMutex();
// return true;
//}
#endregion
#region "READ"
public bool ReadSingle(int address, out Single value)
{
value = 0;
if (Init == false) return false;
var retval = true;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 1;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToSingle(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadDouble(int address, out double value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 1;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToDouble(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadBytes(int address, int size, out byte[] value)
{
var retval = true;
value = new byte[size];
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
reader.Read(value, 0, size);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadByte(int address, out byte value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 1;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = buffer.First();
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadInt16(int address, out Int16 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToInt16(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadInt32(int address, out Int32 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToInt32(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadInt64(int address, out Int64 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToInt64(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadUInt16(int address, out UInt16 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToUInt16(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadUInt32(int address, out UInt32 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToUInt32(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
public bool ReadUInt64(int address, out UInt64 value)
{
var retval = true;
value = 0;
if (Init == false) return false;
var type = value.GetType();
if (MutexWaitOne(ReadTime) == false) return false;
var size = 4;
using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
{
using (var reader = new BinaryReader(stream))
{
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
value = BitConverter.ToUInt64(buffer, 0);
}
}
mutex.ReleaseMutex();
return retval;
}
//public bool Read<T>(int address, out T value) where T : IConvertible
//{
// var retval = true;
// value = default(T);
// var type = value.GetType();
// if (checktype(type) == false) return false;
// if (MutexWaitOne(3000) == false) return false;
// var size = Marshal.SizeOf(typeof(T));
// using (MemoryMappedViewStream stream = mmf.CreateViewStream(address, size))
// {
// using (var reader = new BinaryReader(stream))
// {
// byte[] buffer = new byte[size];
// reader.Read(buffer, 0, size);
// if (type == typeof(Int32))
// value = (T)Convert.ChangeType(BitConverter.ToInt32(buffer, 0), typeof(T));
// else if (type == typeof(UInt32))
// value = (T)Convert.ChangeType(BitConverter.ToUInt32(buffer, 0), typeof(T));
// else if (type == typeof(Int16))
// value = (T)Convert.ChangeType(BitConverter.ToInt16(buffer, 0), typeof(T));
// else if (type == typeof(UInt16))
// value = (T)Convert.ChangeType(BitConverter.ToUInt16(buffer, 0), typeof(T));
// else if (type == typeof(byte))
// value = (T)Convert.ChangeType(buffer[0], typeof(T));
// else if (type == typeof(string))
// value = (T)Convert.ChangeType(System.Text.Encoding.Default.GetString(buffer), typeof(T));
// else retval = false;
// }
// }
// mutex.ReleaseMutex();
// return retval;
//}
#endregion
/// <summary>
/// 지정한 타입이 호환되는 타입인가?
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
//bool checktype(Type value)
//{
// if (value == typeof(Int32)) return true;
// else if (value == typeof(UInt32)) return true;
// else if (value == typeof(Int16)) return true;
// else if (value == typeof(UInt16)) return true;
// else if (value == typeof(byte)) return true;
// else if (value == typeof(string)) return true;
// else return false;
//}
}
}