using Aurora.Api; using AuroraPLC; using System; using System.Threading; using ActUtlType64Lib; namespace AuroraMXComponent { public class MXComponent : PLCNetwork { private readonly Logger Log = new Logger("PLC MXComponent"); private ActUtlType64Class _actUtlType; //private DotUtlType64.DotUtlType64 _dotUtlType; private const int _success = 0; private bool IsConnected = false; public MXComponent() { _actUtlType = new ActUtlType64Class(); //_dotUtlType = new DotUtlType64.DotUtlType64(); } public override void SetInitParams(int logicalStationNo) { _actUtlType.ActLogicalStationNumber = logicalStationNo; } public override bool OpenToPLC() { try { if (IsConnected) { var result = _actUtlType.Close(); IsConnected = !result.Equals(_success); Log.I($"Close: 0x{result:x8} [Hex]"); Thread.Sleep(500); // 미츠비시 MxComponent 문서의 최소 500 [ms] 간격 } //================================================ //_actUtlType.ActLogicalStationNumber = stationNo; var res = _actUtlType.Open(); IsConnected = res.Equals(_success); Log.I($"Open: 0x{res:x8} [Hex]"); if (IsConnected == false) { // 연결 실패 // 타임 아웃 에러이면, 1회 재시도 if (res == 0x0180840B) { Thread.Sleep(500); // 딜레이를 얼마를 줄까... res = _actUtlType.Open(); IsConnected = res.Equals(_success); Log.I($"Open: 2nd trial: 0x{res:x8} [Hex]"); } } return IsConnected; } catch (Exception ex) { Log.E($"Exception from Open: {ex.Message}"); IsConnected = false; return false; } } public override bool CloseToPLC() { try { var res = _actUtlType.Close(); IsConnected = !res.Equals(_success); // 닫기 성공이면, false Log.I($"Close: 0x{res:x8} [Hex]"); Thread.Sleep(500); // 그냥 500 ms 딜레이를 항상 주자 /* if (res == _success) { // 문서상, Close 후, 다시 Open 실행할 때까지 최소 500 ms 이상 간격을 두라고 함 Thread.Sleep(500); } */ } catch (Exception ex) { Log.E($"Exception from Close: {ex.Message}"); // 실패이므로, 연결 flag 도 off 해놓자. IsConnected = false; return false; } // Disconnected --> 성공 return !IsConnected; } // Aurora 프로그램이 종료할 때만 호출이 필요함...(필요없을 것 같은데, 삭제 검토) public override void Terminate() { // Aurora 의 비활성화가 완료된 후에 널 포인터로 정리하자.. // CloseToPLC 에서 널 포인터를 해버리면, 데이터 프로세싱 스레드에서 문제가 발생한다. // 프로그램이 완전히 종료할 때 널을 할까?? 흠... 굳이 필요없을 것 같기도 하고.... _actUtlType = null; Log.I("_actUtlType = null"); } // (out 대신) 지역변수를 생성하지 않기 위해서, ref 로 readData 를 받음 public override bool ReceiveFromPLC(in string devLabel, int readByteSize, ref short[] readData) { /* // 여긴 굳이 try-catch 가 불필요할 것 같은데.. //return mdReceive(pathOfChannel, stationNo, devType, startDevNo, ref readByteSize, ref readData).Equals(_success); // 일단 그냥 테스트용.... // 2 바이트 단위로 읽음 (접미사 2 가 없으면 받는변수는 4바이트여서 post processing 필요, 메뉴얼 참고) var res = _dotUtlType.ReadDeviceBlock2(ref devLabel, readByteSize, ref readData); */ int res = -1; try { res = _actUtlType.ReadDeviceBlock2(devLabel, readByteSize, out readData[0]); } catch (Exception ex) { #if DEBUG //Log.E($"Exception (ReadDeviceBlock2): {ex.StackTrace}; {ex.Message}"); Log.E($"Exception (ReadDeviceBlock2): {ex.Message}"); //Console.WriteLine($"Exception is occured: {ex.StackTrace}; {ex.Message}"); #endif } return res.Equals(_success); } public override bool SendToPLC(in string devLabel, int writeSize, ref short[] writeData) { int res = -1; try { res = _actUtlType.WriteDeviceBlock2(devLabel, writeSize, ref writeData[0]); } catch (Exception ex) { #if DEBUG Log.E($"Exception (WriteDeviceBlock2): {ex.Message}"); #endif } return res.Equals(_success); } //============================================================================ //-------- data update 스레드 이외에서 사용하는 API ------------// //------------ B/W 이외의 장치 수신 public override bool ReceiveDeviceBlock2FromPLC(in string szDevice, int readSize, ref short[] readData) { if (IsConnected) { // 솔더링: 멀티 스레드로 호출되는데, 문제 없었음 return ReceiveFromPLC(in szDevice, readSize, ref readData); } else { return false; } } //=============================================== //-------- MX Component 한정 // 솔더링 코드에서 비트 입력에 write 하는 경우 때문에 업데이트 스레드에서 잠깐 사용 (코드 수정 후 사용안함) public override bool SetDevice2(in string devLabel, short writeData) { int res = -1; try { res = _actUtlType.SetDevice2(devLabel, writeData); } catch (Exception ex) { #if DEBUG Log.E($"Exception (SetDevice2): {ex.Message}"); //Console.WriteLine($"Exception is occured: {ex.StackTrace}; {ex.Message}"); #endif } // 실패에 대한 로그를 남겨야 할까?? if (res.Equals(_success) != true) { // 에러 발생 Log.E($"SetDevice2 fail: 0x{res:x8} [HEX]"); return false; } else { return true; } } } }