using Aurora.Api; using AuroraPLC; using System; using System.Runtime.InteropServices; namespace AuroraMelsecNet { public class MelsecNet : PLCNetwork { private readonly Logger Log = new Logger("PLC MelsecNet"); #region MelsecNet DLL import // MelsecNet data link library // For C# // C:\Windows\SysWOW64 경로에 mdfunc32W.dll 파일 존재함 // 일단은 mdfunc32 로 검증후, mdfunc32w 검토...mdfunc32w 는 64비트를 의미하는걸까? // Charset: 문자열 관련, 인자로 string 사용안하니, 중요하지 않을 것 같은데..??? // SetLastError: 에러를 셋 여부로 에러 처리 관련인듯한데.. [DllImport("MDFUNC32.DLL", EntryPoint = "mdOpen", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdOpen(short chan, short mode, ref long path); [DllImport("MDFUNC32.DLL", EntryPoint = "mdClose", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdClose(long path); [DllImport("MDFUNC32.DLL", EntryPoint = "mdSend", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdSend(long path, short stno, short devtyp, short devno, ref short size, ref short data); [DllImport("MDFUNC32.DLL", EntryPoint = "mdReceive", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdReceive(long path, short stno, short devtyp, short devno, ref short size, ref short data); /* // 현재 주기적 배치 Read/Write 방식상, 개별적인 콜이 불필요하여 일단 주석처리.. [DllImport("MDFUNC32.DLL", EntryPoint = "mdreceiveex", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdReceiveEx(int path, short Netno, short Stno, short Devtyp, short DevNo, ref short Size_Renamed, ref short Buf); [DllImport("MDFUNC32.DLL", EntryPoint = "mdsendex", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdSendEx(int path, short Netno, short Stno, short Devtyp, short DevNo, ref short Size_Renamed, ref short Buf); [DllImport("MDFUNC32.DLL", EntryPoint = "mddevset", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdDevSet(int path, short Stno, short Devtyp, short DevNo); [DllImport("MDFUNC32.DLL", EntryPoint = "mddevrst", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern short mdDevRst(int path, short Stno, short Devtyp, short DevNo); */ #endregion #region 네트워크 설정 관련 // 채널: 51 for NET-H, 151 for NET-G // owner station: 0xFF // remote station: 0x102 .... 0xFF ?? #endregion //public short StationNo { get; private set; } //public short ChannelNo { get; private set; } // 통신 연결된 path 포인터 (C++ 경우); Melsec 용 private long _pathForOpenedLine; private short _channelNo; private short _mode; private short _stationNo; private const int _success = 0; private bool IsConnected = false; public MelsecNet() { //_isSimul = isSimul; } public override void SetInitParams(short channelNo, short mode, short stationNo) { _channelNo = channelNo; _mode = mode; _stationNo = stationNo; } public override bool OpenToPLC() { try { // 장비가 없을 때 에러를 막기 위한 용... // Repair 코드에서도 1회 재시도를 하고 있음... // MX Component 와 비슷하게~~~ if (IsConnected) { var result = mdClose(_pathForOpenedLine); IsConnected = !result.Equals(_success); Log.I($"mdClose: 0x{result:x8} [Hex]"); //Thread.Sleep(500); // Melsec 문서보고 재검토.. } var res = mdOpen(_channelNo, _mode, ref _pathForOpenedLine); IsConnected = res.Equals(_success); Log.I($"mdOpen: 0x{res:x8} [Hex]"); // 1회 재시도.. if (IsConnected == false) { // TODO : 리턴코드 확인 후... } return IsConnected; } catch (Exception ex) { // 일단 무조건 장비가 없을 경우를 가정한다. Log.E($"Exception from mdOpen: {ex.Message}"); IsConnected = false; return false; } } public override bool CloseToPLC() { try { var res = mdClose(_pathForOpenedLine); IsConnected = !res.Equals(_success); // 닫기 성공이면, false Log.I($"mdClose: 0x{res:x8} [Hex]"); // Need 딜레이 ?? } catch (Exception ex) { Log.E($"Exception from mdClose: {ex.Message}"); return !IsConnected; } return !IsConnected; } public override bool ReceiveFromPLC(short devType, short startDevNo, ref short readByteSize, ref short readData) { // 여긴 굳이 try-catch 가 불필요할듯.. return mdReceive(_pathForOpenedLine, _stationNo, devType, startDevNo, ref readByteSize, ref readData).Equals(_success); } public override bool SendToPLC(short devType, short startDevNo, ref short writtenByteSize, ref short writtenData) { return mdSend(_pathForOpenedLine, _stationNo, devType, startDevNo, ref writtenByteSize, ref writtenData).Equals(_success); } } }