I'm still very new to OOP and TwinCat so please bear with me. I'm currently developing the software for a small machine that will be used combined with the TF2000 HMI. Because the Event Grid takes away a lot of work I want to set up the TC3 EventLogger. I understand how you create alarms etc. and I can display them in the HMI Event Grid.
It works great with single events, but now I want to take it further and add the errors of every function block. For example FB_TemperatureController can report overheat, FB_Motor can report a stop error and so on.
How do I setup the event logger so I can send the same error from every instantiated FB?
I thought of creating a FB_FaultHandler:
FUNCTION_BLOCK FB_FaultHandler
VAR
fbEventLogger : FB_TcEventLogger;
aMessages : ARRAY [0..100] OF Fb_TcMessage;
aAlarms : ARRAY [0..100] OF Fb_TcAlarm;
END_VAR
METHOD init
VAR_INPUT
END_VAR
aAlarms[0].CreateEx(Tc_Events.AlarmEvents.Error_Overtemp, TRUE, 0);
aAlarms[1].CreateEx(Error2, TRUE, 0);
aAlarms[2].CreateEx(Error3, TRUE, 0);
aAlarms[3].CreateEx(Error4, TRUE, 0);
aAlarms[4].CreateEx(, TRUE, 0);
aAlarms[5].CreateEx(, TRUE, 0);
aAlarms[6].CreateEx(, TRUE, 0);
There's a few things I don't like about this tho:
METHOD setError
VAR_INPUT
nErrorId: INT;
bErrorActive: BOOL;
END_VAR
FB_FaultHandler
will put it in aAlarms[96]
I haven't really found any real samples about this anywhere. I watched the Webinar but it honestly is described very poorly. I'd be thankful for any help, input or examples of a good event logger.
Off the top of my head with some help of the internet. Don't have a system for compiling at hand. But you could do something like this code below.
Essential there is a baseclass for logging (your FB_FaultHandler). From this all classes with logging functionality can be derived from. It uses reflection for the instance path. I never used reflection in twincat as I usually solve this kind of problem a little different. But it is the most generic solution I guess.
An example for the final class is FB_MyClassesWithLoggingFunctionality.
There is also a small stub for the initialization code in MAIN. You have to initialize and trigger the setting of Info Class FB_SourceInfo. It sets the instance information in the FB_SourceInfo. That is a class that you can handover to the CreateEx Method and should provide the source of the instance information.
In the below example of MAIN the source info would be like -project-.MAIN.fbClass
// -------------- Base class for all classes with logging
{attribute 'reflection'}
FUNCTION_BLOCK FB_FaultHandler
VAR
{attribute 'instance-path'}
{attribute 'noinit'}
sErrorSource : STRING; // make sure that this variable is large enough to hold the path
fbFaultInfo : FB_SourceInfo;
fbEventLogger : FB_TcEventLogger;
aMessages : ARRAY [0..100] OF Fb_TcMessage;
aAlarms : ARRAY [0..100] OF Fb_TcAlarm;
END_VAR
METHOD InitInfo
fbFaultInfo.InitInfo(sErrorSource);
// example: use faultInfo
aAlarms[0].CreateEx(Tc_Events.AlarmEvents.Error_Overtemp, TRUE, fbFaultInfo);
END_METHOD
METHOD logError
VAR_INPUT
errorId : INT;
END_VAR
END_METHOD
// Raise error
END_FUNCTION_BLOCK
// ------------ FB for source Info
FUNCTION_BLOCK FB_SourceInfo IMPLEMENTS I_TcSourceInfo
VAR
sSourceInfo : STRING
METHOD InitInfo
VAR_INPUT
source : STRING
END_VAR
sSourceInfo := source;
END_METHOD
END_FUNCTION_BLOCK
// ------------------ Final class that has logging functions
FUNCTION_BLOCK FB_MyClassesWithLoggingFunctionality EXTENDS FB_FaultHandler
METHOD DoSomething
VAR_INPUT
END_VAR
IF bError then
logError(id);
END_IF
END_METHOD
// Usage
PROGRAM MAIN
VAR
fbClass : FB_MyClassesWithLoggingFunctionality;
bInit : BOOL;
END_VAR
IF NOT bInit THEN
fbClass.InitInfo();
bInit := FALSE;
END_IF
END_PROGRAM