to3796zw 7fc11f2602 fix: AjinIO.IsConnected 반전 로직 정정
AxlGetBoardStatus가 SUCCESS일 때 미연결로 반환하던 반전 버그를
정정(실제 Ajin 연결 시 OnMonitoring 폴링이 스킵되던 원인).
연동해 OnMonitoring 미연결 가드를 앞으로 정리.
2026-06-20 10:14:18 +09:00

635 lines
22 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace AuroraIO.AJINEXTEK
{
public class AjinIO : IOUnit
{
public class IOModuleInfo
{
public enum eModuleType { Digital, Analog };
#region IO Enumerator Definitions(IPG YLS, LBAD)
public enum eADIAddress
{
LaserReady,
EmissionStatus,
LaserError,
LaserIsOn,
ProgramActive,
Warning,
LaserModuleAlarm,
LaserAssigned,
LBADReadyStatus,
LBADJudgementComplete,
LBADJudgeOK,
LBADJudgeWARNING,
LBADJudgeNG,
LBADJudgeNA,
LDDError = 27,
LaserEMO_1,
LaserEMO_2,
LeakSensorHead,
LeakSensorChiller,
DICount
}
public enum eADOAddress
{
ProgramStart,
PCcontrolEnable,
ResetAlarm,
GuideLaserEnable,
AnalogControl,
ProgramStop,
LaserOn,
PulseMode,
PCLBADReadyStatus,
PCLBADWeldingTrigger,
PCLBADWeldingStop,
PCLBADJudgementCompleteAck,
DOCount
}
#endregion
public IOModuleInfo(int no, int iCount, int oCount, eModuleType type, int inputStart, int outputStart)
{
ioModuleNo = no;
inputCount = iCount;
outputCount = oCount;
ioModuleType = type;
inputStartIndex = inputStart;
outputStartIndex = outputStart;
}
eModuleType ioModuleType;
public eModuleType IoModuleType
{
get { lock (this) { return ioModuleType; } }
set { lock (this) { ioModuleType = value; } }
}
int ioModuleNo;
public int IOModuleNo
{
get { lock (this) { return ioModuleNo; } }
set { lock (this) { ioModuleNo = value; } }
}
int inputCount;
public int InputCount
{
get { lock (this) { return inputCount; } }
set { lock (this) { inputCount = value; } }
}
int outputCount;
public int OutputCount
{
get { lock (this) { return outputCount; } }
set { lock (this) { outputCount = value; } }
}
int inputStartIndex;
public int InputStartIndex
{
get { lock (this) { return inputStartIndex; } }
set { lock (this) { inputStartIndex = value; } }
}
int outputStartIndex;
public int OutputStartIndex
{
get { lock (this) { return outputStartIndex; } }
set { lock (this) { outputStartIndex = value; } }
}
}
List<IOModuleInfo> ioModulInfoList = new List<IOModuleInfo>();
#region 추상 함수 선언
public override int Open(string iP)
{
int error = 0;
string msg = "";
try
{
if (CAXL.AxlIsOpened() == (int)AXT_BOOLEAN.FALSE)
{
error = (int)CAXL.AxlOpen(7);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("IO Device Open Fail!!({0})", GetErrorMessage(error));
return error;
}
}
//LoadIOTable();
return 0;
}
catch (Exception e)
{
return -1;
}
}
public override void Close()
{
try
{
if (CAXL.AxlIsOpened() == (int)AXT_BOOLEAN.TRUE)
CAXL.AxlClose();
}
catch { }
}
public AjinIO()
{
}
public override int GetDICount()
{
int count = 0;
foreach(IOModuleInfo module in ioModulInfoList)
{
if(module.IoModuleType == IOModuleInfo.eModuleType.Digital)
{
count += module.InputCount;
}
}
return count;
}
public override int GetDOCount()
{
int count = 0;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (module.IoModuleType == IOModuleInfo.eModuleType.Digital)
{
count += module.OutputCount;
}
}
return count;
}
public override int GetAICount()
{
int count = 0;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (module.IoModuleType == IOModuleInfo.eModuleType.Analog)
{
count += module.InputCount;
}
}
return count;
}
public override int GetAOCount()
{
int count = 0;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (module.IoModuleType == IOModuleInfo.eModuleType.Analog)
{
count += module.OutputCount;
}
}
return count;
}
public override void Instance(string mappingFolder)
{
IOMappingFolder = mappingFolder;
//LoadIOTable();
}
public override int Initialize()
{
int error = 0;
string msg = "";
int dioModuleCount = 0;
int aioModuleCount = 0;
#region DIO
error = (int)CAXD.AxdInfoGetModuleCount(ref dioModuleCount);
if ((error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS) && (error != (int)AXT_FUNC_RESULT.AXT_RT_DIO_NOT_MODULE))
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
//messageDlg.messageDlg.RunDlg(msg, true, MessageDlg.DialogMode.MODAL);
return error;
}
int boardNo = 0;
int modulePos = 0;
uint moduleId = 0;
int moduleNo = 0;
int inputCount = 0;
int outputCount = 0;
int inputIndex = 0;
int outputIndex = 0;
if (0 < dioModuleCount)
{
ioModulInfoList.Clear();
for (int i = 0; i < dioModuleCount; i++)
{
error = (int)CAXD.AxdInfoGetModule(i, ref boardNo, ref modulePos, ref moduleId);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXD.AxdInfoGetModuleNo(boardNo, modulePos, ref moduleNo);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXD.AxdInfoGetInputCount(moduleNo, ref inputCount);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXD.AxdInfoGetOutputCount(moduleNo, ref outputCount);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
#region R&D 장비에서 설정문제인지 IO보드가 중복검색되어서, 예외처리 추가
bool isAlreadyExists = false;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (moduleNo == module.IOModuleNo)
{
isAlreadyExists = true;
break;
}
}
if (isAlreadyExists) continue;
#endregion
IOModuleInfo tempModule = new IOModuleInfo(moduleNo, inputCount, outputCount, IOModuleInfo.eModuleType.Digital, inputIndex, outputIndex);
ioModulInfoList.Add(tempModule);
inputIndex += inputCount;
outputIndex += outputCount;
}
}
#endregion
#region AIO
error = (int)CAXA.AxaInfoGetModuleCount(ref aioModuleCount);
if ((error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS) && (error != (int)AXT_FUNC_RESULT.AXT_RT_AIO_NOT_MODULE))
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
//messageDlg.messageDlg.RunDlg(msg, true, MessageDlg.DialogMode.MODAL);
return error;
}
if (0 < aioModuleCount)
{
boardNo = 0;
modulePos = 0;
moduleId = 0;
moduleNo = 0;
inputCount = 0;
outputCount = 0;
inputIndex = 0;
outputIndex = 0;
for (int i = 0; i < aioModuleCount; i++)
{
error = (int)CAXA.AxaInfoGetModule(i, ref boardNo, ref modulePos, ref moduleId);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXA.AxaInfoGetModuleNo(boardNo, modulePos, ref moduleNo);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXA.AxaInfoGetInputCount(moduleNo, ref inputCount);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
error = (int)CAXA.AxaInfoGetOutputCount(moduleNo, ref outputCount);
if (error != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("Read Module Count Error!!({0})", GetErrorMessage(error));
return error;
}
#region R&D 장비에서 설정문제인지 IO보드가 중복검색되어서, 예외처리 추가
bool isAlreadyExists = false;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (moduleNo == module.IOModuleNo)
{
isAlreadyExists = true;
break;
}
}
if (isAlreadyExists) continue;
#endregion
IOModuleInfo tempModule = new IOModuleInfo(moduleNo, inputCount, outputCount, IOModuleInfo.eModuleType.Analog, inputIndex, outputIndex);
ioModulInfoList.Add(tempModule);
inputIndex += inputCount;
outputIndex += outputCount;
}
}
#endregion
//IO 레벨 세팅
//error = SetIoLevel();
//Interrupt 세팅
//error = SetIntterrupt();
return 0;
}
public override bool IsConnected()
{
int err = (int)CAXL.AxlGetBoardStatus(0);
return err == (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS;
}
#endregion
public override int GetDoArray(ref bool[] array)
{
uint data = 0;
int lastIndex = 0;
foreach (IOModuleInfo module in ioModulInfoList)
{
if(module.IoModuleType == IOModuleInfo.eModuleType.Digital && module.OutputCount !=0)
{
int err = (int)CAXD.AxdoReadOutportDword(module.IOModuleNo, 0, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
return err;
}
BitArray arr = new BitArray(BitConverter.GetBytes(data));
arr.CopyTo(array, lastIndex);
lastIndex += module.OutputCount;
}
}
return 0;
}
public override int GetDiArray(ref bool[] array)
{
uint data = 0;
foreach (IOModuleInfo module in ioModulInfoList)
{
if (module.IoModuleType == IOModuleInfo.eModuleType.Digital && module.InputCount != 0)
{
int err = (int)CAXD.AxdiReadInportDword(module.IOModuleNo, 0, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
return err;
}
//BitArray arr = new BitArray(BitConverter.GetBytes(data));
// 1안 ) 220118 이준혁Y 테스트 필요.
//BitArray arr = new BitArray(module.InputCount, false);
//for (int i = 0; i < module.InputCount; i++)
//{
// int selectBitToInt = (int)(Math.Pow(2, i));
// int selectedBitToInt = (int)data & selectBitToInt;
// if (selectedBitToInt == selectBitToInt) arr[i] = true;
// else arr[i] = false;
//}
// 2안) 220118 카운트 크기에 따라서, BitArray 다른 것으로 쓰게끔.
Byte tempByte = 0;
UInt16 tempUInt = 0;
BitArray arr = new BitArray(module.InputCount, false);
if (module.InputCount == 8)
{
tempByte = Convert.ToByte(data);
arr = new BitArray(BitConverter.GetBytes(tempByte).ToArray());
}
else if (module.InputCount == 16)
{
tempUInt = Convert.ToUInt16(data);
arr = new BitArray(BitConverter.GetBytes(tempUInt));
}
else if (module.InputCount == 32)
{
arr = new BitArray(BitConverter.GetBytes(data));
}
else;
arr.CopyTo(array, module.InputStartIndex);
}
}
return 0;
}
public override int ReadDoBit(int index, ref bool bit)
{
uint data = 0;
int err = (int)CAXD.AxdoReadOutport(index, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
return err;
}
bit = Convert.ToBoolean(data);
return 0;
}
public override int ReadDiBit(int index, ref bool bit)
{
uint data = 0;
int err = (int)CAXD.AxdiReadInport(index, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
return err;
}
bit = Convert.ToBoolean(data);
return 0;
}
public override bool ReadDoBit(int index)
{
//현재 사용하지 않아서 추후 구현
//return true;
//[추후 구현] return true 스텁 의존 코드 확인 후 아래로 교체(ReadDiBit(int) 패턴)
uint data = 0;
int err = (int)CAXD.AxdoReadOutport(index, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
throw new Exception(string.Format("ERR_IO_FAIL_TO_GET_BIT;ERROR CODE:{0}", err));
}
return Convert.ToBoolean(data);
}
public override bool ReadDiBit(int index)
{
uint data = 0;
int err = (int)CAXD.AxdiReadInport(index, ref data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
throw new Exception(string.Format("ERR_IO_FAIL_TO_GET_BIT;ERROR CODE:{0}", err));
}
return Convert.ToBoolean(data);
}
public override int WriteDoBit(int index, bool bit)
{
uint data = Convert.ToUInt16(bit);
int err = (int)CAXD.AxdoWriteOutport(index, data);
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
return err;
}
return 0;
}
public override void ClearList()
{
ListDI.Clear();
ListDO.Clear();
}
//int SetIoLevel()
//{
// string msg = string.Empty;
// int rv = 0;
// //AJin IO에서 접점 변경은 Active를 High(1) 또는 Low(0) Level 설정한다.
// //기본적으로 NO(Normal Open)접점이 Active상태에서 high(1) Level이므로 설정을 아래와 같이 한다.
// //input contact
// foreach (IOModuleInfo ioModule in ioModulInfoList)
// {
// for (int i = 0; i < ioModule.InputCount; i++)
// {
// uint uLevel = (uint)(ListDI[ioModule.InputStartIndex + i].ActiveLevel == InfoIO.ActiveLevelType.High ? 1 : 0);
// rv = (int)CAXD.AxdiLevelSetInportBit(ioModule.IOModuleNo, i, uLevel);
// if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
// {
// msg = string.Format("{0} Set DI Active Level Error({1})", ListDI[ioModule.InputStartIndex + i].Index, GetErrorMessage(rv));
// return rv;
// }
// }
// for (int i = 0; i < ioModule.OutputCount; i++)
// {
// uint uLevel = (uint)(ListDO[ioModule.OutputStartIndex + i].ActiveLevel == InfoIO.ActiveLevelType.High ? 1 : 0);
// rv = (int)CAXD.AxdoLevelSetOutportBit(ioModule.IOModuleNo, i, uLevel);
// if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
// {
// msg = string.Format("{0} Set Active Level Error({1})", ListDO[ioModule.OutputStartIndex + i].Index, GetErrorMessage(rv));
// return rv;
// }
// }
// }
// return rv;
//}
int SetIntterrupt()
{
string msg = string.Empty;
int rv = 0;
foreach (IOModuleInfo ioModule in ioModulInfoList)
{
//인터럽트 처리 사용 여부 설정
rv = (int)CAXD.AxdiInterruptSetModuleEnable(ioModule.IOModuleNo, 1);
if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("ModuleNo :{0}; Set Interrupted Error({1})",ioModule.IOModuleNo, GetErrorMessage(rv));
return rv;
}
uint eventNo=0;
//인터럽트 처리 방법 설정
rv = (int)CAXD.AxdiInterruptSetModule(ioModule.IOModuleNo,(IntPtr)null, 0, InterruptCallbackFunction, ref eventNo);
if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("ModuleNo :{0}; Set Interrupted Error({1})", ioModule.IOModuleNo, GetErrorMessage(rv));
return rv;
}
for (int i = 0; i < ioModule.InputCount; i++)
{
//Rising Edge 설정
rv = (int)CAXD.AxdiInterruptEdgeSetBit(ioModule.IOModuleNo, i,1,1);
if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("IO Index :{0}; Set Interrupted Error({1})", ListDI[ioModule.InputStartIndex + i].Index, GetErrorMessage(rv));
return rv;
}
//Falling Edge 설정
rv = (int)CAXD.AxdiInterruptEdgeSetBit(ioModule.IOModuleNo, i, 0, 1);
if (rv != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
{
msg = string.Format("IO Index :{0}; Set Interrupted Error({1})", ListDI[ioModule.InputStartIndex + i].Index, GetErrorMessage(rv));
return rv;
}
}
}
return rv;
}
#region ErrorMessage
public string GetErrorMessage(int errCode)
{
return Enum.ToObject(typeof(AXT_FUNC_RESULT), errCode).ToString();
}
#endregion ErrorMessage
}
}