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 StartAction; protected Func 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 changeindex = new List(); 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 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(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(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 /// /// 지정한 타입이 호환되는 타입인가? /// /// /// //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; //} } }