TYPE Tag_DigitalIn_Cfg :
STRUCT
nSlotNo : INT := 0; (* Slot index: 0 = onboard, 1..4 = expansion slots *)
nPinNo : INT := 0; (* Pin index: 0 to (max pin per module -1) *)
nActiveEdge : INT := 0; (* Trigger level: 0 = low, 1 = high *)
uNoteRef : UINT := 0; (* Reference to descriptive text ID *)
nDebounceTarget : INT := CNST_DIN_DEBOUNCE_CNT;
bPrevRaw : BOOL := 0;
bCurrRaw : BOOL := 0;
nCurrDebounce : INT := 0;
nStoredDebounce : INT := 0;
END_STRUCT
END_TYPE
TYPE Tag_DigitalOut_Cfg :
STRUCT
nActive : INT := 1;
nSlotNo : INT := 0;
nPinNo : INT := 0;
nActiveEdge : INT := 0;
uNoteRef : UINT := 0;
nCheckEn : INT := 0; (* Output verification toggle: 0 = off, 1 = on *)
nCheckInIdx : INT := 0; (* Index of linked input in status array for feedback check *)
lrPreCheckDel_S : LREAL := 0;
lrCheckDel_S : LREAL := 0;
END_STRUCT
END_TYPE
TYPE Tag_DigitalIn_Stat :
STRUCT
bValidState : BOOL; (* Filtered and normalized input state: 1 = active *)
END_STRUCT
END_TYPE
TYPE Tag_DigitalOut_Stat :
STRUCT
bRequestedState : BOOL;
bValidatedState : BOOL;
END_STRUCT
END_TYPE
VAR_GLOBAL CONSTANT
CNST_DIN_DEBOUNCE_CNT : INT := 3;
END_VAR
VAR_GLOBAL
STS_DIN : ARRAY[1..CNST_DIN_TOTAL] OF Tag_DigitalIn_Stat;
STS_DOUT : ARRAY[1..CNST_DOUT_TOTAL] OF Tag_DigitalOut_Stat;
g_atDIN_Cfg : ARRAY[1..CNST_DIN_TOTAL] OF Tag_DigitalIn_Cfg;
g_atDOUT_Cfg : ARRAY[1..CNST_DOUT_TOTAL] OF Tag_DigitalOut_Cfg;
END_VAR
VAR_GLOBAL CONSTANT
CNST_DIN_TOTAL : INT := 52;
CNST_DOUT_TOTAL : INT := 28;
END_VAR
VAR_GLOBAL
END_VAR
Init_DIN;
Init_DOUT;
idxExpSlot := 1;
FOR idxAll := 1 TO CNST_DIN_TOTAL DO
g_atDIN_Cfg[idxAll].uNoteRef := idxAll + 12000;
IF idxAll <= CNST_LOCAL_DIN_CNT THEN
g_atDIN_Cfg[idxAll].nSlotNo := 0;
g_atDIN_Cfg[idxAll].nPinNo := idxAll - 1;
g_atDIN_Cfg[idxAll].nActiveEdge := 0;
ELSE
nOffset := idxAll - CNST_LOCAL_DIN_CNT - (idxExpSlot - 1)*CNST_EXP_DIN_PER_SLOT - 1;
g_atDIN_Cfg[idxAll].nSlotNo := idxExpSlot;
g_atDIN_Cfg[idxAll].nPinNo := nOffset;
g_atDIN_Cfg[idxAll].nActiveEdge := 1;
IF nOffset >= (CNST_EXP_DIN_PER_SLOT - 1) THEN
idxExpSlot := idxExpSlot + 1;
END_IF
END_IF
END_FOR
fh := SysFileOpen(g_str_DINCfgPath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE_DIN := TRUE;
ELSE
szCfg := SIZEOF(g_atDIN_Cfg);
IF szCfg <> SysFileWrite(fh, ADR(g_atDIN_Cfg[1]), szCfg) THEN
ALARM_FILE_WRITE_DIN := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;
idxExpSlot := 1;
FOR idxAll := 1 TO CNST_DOUT_TOTAL DO
g_atDOUT_Cfg[idxAll].uNoteRef := idxAll + 13000;
IF idxAll <= CNST_LOCAL_DOUT_CNT THEN
g_atDOUT_Cfg[idxAll].nSlotNo := 0;
g_atDOUT_Cfg[idxAll].nPinNo := idxAll - 1;
g_atDOUT_Cfg[idxAll].nActiveEdge := 0;
ELSE
nOffset := idxAll - CNST_LOCAL_DOUT_CNT - (idxExpSlot - 1)*CNST_EXP_DOUT_PER_SLOT - 1;
g_atDOUT_Cfg[idxAll].nSlotNo := idxExpSlot;
g_atDOUT_Cfg[idxAll].nPinNo := nOffset;
g_atDOUT_Cfg[idxAll].nActiveEdge := 1;
IF nOffset >= (CNST_EXP_DOUT_PER_SLOT - 1) THEN
idxExpSlot := idxExpSlot + 1;
END_IF
END_IF
END_FOR
fh := SysFileOpen(g_str_DOUTCfgPath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE_DOUT := TRUE;
ELSE
szCfg := SIZEOF(g_atDOUT_Cfg);
IF szCfg <> SysFileWrite(fh, ADR(g_atDOUT_Cfg[1]), szCfg) THEN
ALARM_FILE_WRITE_DOUT := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;
VAR_GLOBAL
g_fbIOConfig : IO_CONFIG;
g_fbIOConfig_Ctrl : IO_CONFIG_CTRL;
END_VAR
ReadIOCount;
ReadIOSlotAssign;
ReadIOUserLinks;
ReadIOSetMode;
UserLinkProcess;
SaveIOCfgFiles;
diFileSize := SysFileGetSize(str_IOCountPath);
diExpectedSize := 4;
IF diFileSize <> diExpectedSize THEN
ALARM_GET[10,9] := TRUE;
bReadFail[1] := TRUE;
ELSE
dwFileSize := DINT_TO_DWORD(diFileSize);
fh := SysFileOpen(str_IOCountPath, 'r');
IF fh = 0 THEN
ALARM_GET[10,9] := TRUE;
bReadFail[2] := TRUE;
ELSE
IF dwFileSize <> SysFileRead(fh, ADR(IOCount[1]), dwFileSize) THEN
ALARM_FILE_READ := TRUE;
ALARM_GET[10,9] := TRUE;
bReadFail[3] := TRUE;
END_IF
SysFileClose(fh);
END_IF
END_IF
fh := 0;
FOR idxSlot := 1 TO IOCount[1] DO
FOR idxPin := 1 TO 16 DO
nLinkIdx := 16*idxSlot + idxPin - 16;
nUserTarget := IO_UserLinks[nLinkIdx];
IF nUserTarget <> 0 THEN
IF IO_SetMode[nLinkIdx] = 0 THEN
IF GTN_GetDiPhysicCustom(1, IO_SlotAssign[idxSlot], MC_GPI, idxPin, ADR(abRawValues[idxPin]), 1) <> 0 THEN
ALARM_GET_DI := TRUE;
ALARM_GET[7,1] := TRUE;
END_IF
IF nUserTarget = 56 THEN
IF nDebounceStep = 0 THEN
nDebounceStep := 1;
bDebouncePrev := abRawValues[idxPin];
ELSE
IF nDebounceStep < 2 THEN
IF bDebouncePrev = abRawValues[idxPin] THEN
nDebounceStep := nDebounceStep + 1;
ELSE
nDebounceStep := 0;
END_IF
END_IF
END_IF
IF nDebounceStep = 2 THEN
g_arUserVars[nUserTarget] := 1 - abRawValues[idxPin];
nDebounceStep := 0;
END_IF
ELSE
g_arUserVars[nUserTarget] := 1 - abRawValues[idxPin];
END_IF
ELSE
nSetVal := BOOL_TO_INT(g_arUserVars[nUserTarget] = 0);
IF GTN_SetDoPhysicCustom(1, IO_SlotAssign[idxSlot], MC_GPO, idxPin, ADR(nSetVal), 1) <> 0 THEN
ALARM_SET_DO := TRUE;
ALARM_GET[9,1] := TRUE;
END_IF
END_IF
END_IF
END_FOR
END_FOR
awWin[1] := awWin1;
awWin[2] := awWin2;
awWin[3] := awWin3;
awWin[4] := awWin4;
IF IOCount[2] <> 0 THEN
FOR idxGlink := 1 TO IOCount[2] DO
FOR idxGlinkIn := 1 TO 16 DO
nLinkIdx := 32*idxGlink + idxGlinkIn - 32 + 16*IOCount[1];
nUserTarget := IO_UserLinks[nLinkIdx];
IF nUserTarget <> 0 THEN
g_arUserVars[nUserTarget] := WORD_TO_REAL(SHR(awWin[idxGlink], idxGlinkIn-1) AND 16#0001);
END_IF
END_FOR
FOR idxGlinkOut := 17 TO 32 DO
nLinkIdx := 32*idxGlink + idxGlinkOut - 32 + 16*IOCount[1];
nUserTarget := IO_UserLinks[nLinkIdx];
IF nUserTarget <> 0 THEN
nOutBitPos := idxGlinkOut - 17;
bCurrentBit := (SHR(awGlinkOut[idxGlink], nOutBitPos) AND 16#0001) <> 0;
bRequestedBit := g_arUserVars[nUserTarget] = 1;
IF bCurrentBit AND NOT bRequestedBit THEN
awGlinkOut[idxGlink] := awGlinkOut[idxGlink] - REAL_TO_WORD(EXPT(2, nOutBitPos));
ELSIF NOT bCurrentBit AND bRequestedBit THEN
awGlinkOut[idxGlink] := awGlinkOut[idxGlink] + REAL_TO_WORD(EXPT(2, nOutBitPos));
END_IF
END_IF
END_FOR
END_FOR
END_IF
awGlinkOut1 := awGlinkOut[1];
awGlinkOut2 := awGlinkOut[2];
awGlinkOut3 := awGlinkOut[3];
awGlinkOut4 := awGlinkOut[4];
fh := SysFileOpen(str_IOSlotPath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE := TRUE;
ELSE
szWrite := 32;
IF szWrite <> SysFileWrite(fh, ADR(IO_SlotAssign[1]), szWrite) THEN
ALARM_FILE_WRITE := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;
fh := SysFileOpen(str_IOUserLinksPath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE := TRUE;
ELSE
szWrite := 640;
IF szWrite <> SysFileWrite(fh, ADR(IO_UserLinks[1]), szWrite) THEN
ALARM_FILE_WRITE := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;
fh := SysFileOpen(str_IOCountPath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE := TRUE;
ELSE
szWrite := 4;
IF szWrite <> SysFileWrite(fh, ADR(IOCount[1]), szWrite) THEN
ALARM_FILE_WRITE := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;
fh := SysFileOpen(str_IOSetModePath, 'w');
IF fh = 0 THEN
ALARM_FILE_WRITE := TRUE;
ELSE
szWrite := 400;
IF szWrite <> SysFileWrite(fh, ADR(IO_SetMode[1]), szWrite) THEN
ALARM_FILE_WRITE := TRUE;
END_IF
SysFileClose(fh);
END_IF
fh := 0;