2026-01-26 14:51:28 +09:00

168 lines
6.7 KiB
C#

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;
}
}
}
}