I am trying to reuse a FB in Beckhoff that I used in Codesys for years. Beckhoff is based on Codesys, therefore I did not expect any problems. I think the error has something to do with a type conversion that is possible in Codesys but not in Beckhoff. Error: Cannot convert type 'UDINT' to type 'POINTER TO BOOL'.
Underneath my code can be found. This FB has worked for 5+ years in multiple projects already with PLC's from IFM.
FUNCTION_BLOCK FC_AlarmsHandler
VAR_INPUT
LI_bIN: BOOL;
/// Reset Alarms bits - only Alarms that are acknowledged
LI_bReset: BOOL;
/// Acknowledge all active Alarms bits at once
LI_bAckAll: BOOL;
/// Hold time of new alarm
LI_rHoldTimeNewAlarms: REAL;
/// Base address of Alarms group struct
LI_adrAlarmsGroup: DWORD;
/// Number of Alarms group elements
LI_sizeofAlarmsGroup: UINT;
/// Base address of Alarms struct
LI_adrAlarms: DWORD;
/// Base address of Alarms old array of bool
LI_adrAlarmsOld: DWORD;
/// Base address of Alarms hold array of bool
LI_adrAlarmsHold: DWORD;
/// Base address of Alarms acknowledge array of bool
LI_adrAlarmsAck: DWORD;
LI_adrAlarmsText: POINTER TO STRING(64);
END_VAR
VAR_OUTPUT
LQ_bOUT: BOOL;
/// New Alarm -> this output is one cycle high
LQ_bNewAlarm: BOOL;
/// When an alarm is active, this output is high
LQ_bAlarmActive: BOOL;
/// Alarm gone -> this output is one cycle high
LQ_bAlarmGone: BOOL;
END_VAR
VAR
LT_bInit: BOOL;
/// offset for group address
LT_adrOffsetGroup: DWORD;
LT_iNumberOfAlarmGroupElements: UINT;
/// Number of lines for alarm visualization table in Hmi
LT_iNumberOfHmiLines: INT;
/// Number of lines for alarm history visualization table in Hmi
LT_iNumberOfHmiHistoryLines: INT;
LT_ptAlarms: POINTER TO BOOL;
LT_ptAlarmsOld: POINTER TO BOOL;
LT_ptAlarmsHold: POINTER TO BOOL;
LT_ptAlarmsAck: POINTER TO BOOL;
LT_ptAlarmsText: POINTER TO STRING(64);
LT_iCounterAlarmsElements: INT;
/// Timer for holding new alarm
fbTofNewAlarm: TOF;
END_VAR
LQ_bOUT:=LI_bIN;
// Init
IF LT_bInit = FALSE THEN
LT_adrOffsetGroup := LI_adrAlarmsGroup - LI_adrAlarms;
LT_iNumberOfAlarmGroupElements := LI_sizeofAlarmsGroup / SIZEOF(LT_ptAlarms^);
// Alarm array for HMI
LT_iNumberOfHmiLines := GDI_Alarms.iNumberOfHmiLines;
// Alarm history array for HMI
LT_iNumberOfHmiHistoryLines := GDI_Alarms.iNumberOfHmiHistoryLines;
LT_bInit := TRUE;
END_IF
(***************************************************************************)
(* Alarm handling *)
(***************************************************************************)
[HERE I AM HAVING MY PROBLEMS]
// Init new scan cycle
LT_ptAlarms := LI_adrAlarms + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarms^));
LT_ptAlarmsText := LI_adrAlarmsText + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsText^));
LT_ptAlarmsOld := LI_adrAlarmsOld + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsOld^));
LT_ptAlarmsHold := LI_adrAlarmsHold + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsHold^));
LT_ptAlarmsAck := LI_adrAlarmsAck + (LT_adrOffsetGroup * SIZEOF(LT_ptAlarmsAck^));
LQ_bNewAlarm:= FALSE;
LQ_bAlarmActive := FALSE;
LQ_bAlarmGone := FALSE;
FOR LT_iCounterAlarmsElements := 1 TO LT_iNumberOfAlarmGroupElements DO // Scan all data of group
// Check for new alarms
IF LT_ptAlarms^ AND NOT LT_ptAlarmsOld^ THEN
LQ_bNewAlarm:= TRUE;
END_IF
// Reset current alarms
IF LI_bReset AND LT_ptAlarmsAck^ AND NOT LT_ptAlarms^ THEN
LT_ptAlarms^ := FALSE;
ELSE
LT_ptAlarms^ := LT_ptAlarms^ OR LT_ptAlarmsOld^; (* keep alarms true *)
END_IF
// Hold new alarms
IF fbTofNewAlarm.Q = TRUE THEN
LT_ptAlarmsHold^ := LT_ptAlarms^ OR LT_ptAlarmsHold^;
ELSE
LT_ptAlarmsHold^ := LT_ptAlarms^;
END_IF
// Acknowlegde current alarms
IF LI_bAckAll THEN
LT_ptAlarmsAck^ := LT_ptAlarms^;
END_IF
// check if alarm is gone
IF NOT LT_ptAlarms^ AND LT_ptAlarmsOld^ THEN
LQ_bAlarmGone := TRUE;
END_IF
// Alarms active
IF LT_ptAlarms^ THEN
LQ_bAlarmActive:= TRUE;
END_IF
// Save old value
LT_ptAlarmsOld^ := LT_ptAlarms^;
// Next element
LT_ptAlarms := LT_ptAlarms + SIZEOF(LT_ptAlarms^); // Pointer to next element
LT_ptAlarmsText := LT_ptAlarmsText + SIZEOF(LT_ptAlarmsText^); // Pointer to next element
LT_ptAlarmsOld := LT_ptAlarmsOld + SIZEOF(LT_ptAlarmsOld^); // Pointer to next element
LT_ptAlarmsHold := LT_ptAlarmsHold + SIZEOF(LT_ptAlarmsHold^); // Pointer to next element
LT_ptAlarmsAck := LT_ptAlarmsAck + SIZEOF(LT_ptAlarmsAck^); // Pointer to next element
END_FOR
fbTofNewAlarm(in:= LQ_bNewAlarm, PT:= REAL_TO_TIME(LI_rHoldTimeNewAlarms), Q=> , ET=> );
I already tried to add a conversion UDINT_TOPBOOL, UDINT_TODWORD (because of standard pointer datatype) but this did not work.
I strongly suspect you have been using a 32-bit version of CODESYS for all these years, and are now moving to a 64-bit Beckhoff PLC.
If so, your problem is not caused by moving from CODESYS to TwinCAT, but moving from 32 bits to 64 bits. Try it for yourself : go back to CODESYS, and choose any 64-bit runtime. You will get the same error as in TwinCAT when you compile.
You probably should not use DWORD variables to pass addresses around. Use "POINTER TO". Better yet, use "REFERENCE TO". This will compile and work across different CPU architectures.
You seem to be calculating the addresses of many variables that are found in a single structure using offsets, rather than having one single pointer (or reference) to the structure and using "." to access its fields. I have not fully analyzed your code, but it seems to me it would greatly simplify it as you would get rid of all pointer calculations and offload this work to the compiler.