Skip to content

Component Alarms

This section will build upon the information covered in the Simple Alarms above; however, we will now implement alarms at the component level within the SPT Framework. If you did not add the SPT Base Types library before, please do so before continuing.

The creation of the tmc file will follow the same process, but the idea of creating separate files for each component becomes more important for portability of the component. Create a tmc file for a component with the following events:

Component Alarms

In the Simple Alarm document, we placed the code directly in the Main POU, for this example we will first need to create a Machine Module and add a Component to it. Start a new project (or use the existing one from above) and add the following libraries as needed: SPT Base Types, Tc3_PackML_V2, SPT Event Logger, and TC3_EventLogger.

Create a Component

Add a new POU named Component that EXTENDS FB_ComponentBase and include the following variable declarations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
FUNCTION_BLOCK Component EXTENDS FB_ComponentBase
VAR
    ComponentAlarms     : ARRAY[1..COMPONENT_ALARM_COUNT] OF FB_TcAlarm;
    testCritical        : BOOL;
    testError           : BOOL;
    testWarning         : BOOL;
    testInfo            : BOOL;
    testVerbose         : BOOL;
    clearAlarms         : BOOL;
END_VAR

VAR CONSTANT
    COMPONENT_ALARM_COUNT : UDINT := 6; 
END_VAR

The size of the Array of ComponentAlarms must match the tmc file, as each index of the array represents one Event in the tmc, the array declaration in the PLC starts at 1 because we have no need to Raise the InitReferenceEvent.

CyclicLogic

Add the CyclicLogic method to the Component with the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
IF NOT _InitComplete THEN
    _InitComplete := Initialize();
    RETURN;
END_IF

SUPER^.CyclicLogic();

(*
// The following code must be called after SUPER^.CyclicLogic();
*)

// Update alarm severity from this component
_CurrentAlarmSeverity := F_GetMaxSeverityRaised(
    Alarms := ComponentAlarms,
    CurrentSeverity := _CurrentAlarmSeverity);

_Error := _CurrentAlarmSeverity >= TcEventSeverity.Error;

The _CurrentAlarmSeverity is set to Verbose in the Super^.CyclicLogic() and therefore it must be called within the component after the call to the base class, otherwise it will never get reset.

CreateEvents

Add the CreateEvents method with the following code:

1
2
3
4
5
6
F_CreateAllEventsInClass(Alarms     := ComponentAlarms,
                        ClassSize   := SIZEOF(TC_EVENTS.ComponentEvents),
                        pInitEvent  := ADR(TC_EVENTS.ComponentEvents.InitReferenceEvent),
                        Prefix      := Name);

SUPER^.CreateEvents();

This code provides a reference to the InitReferenceEvent in the tmc file and will create a list of events specific to this component. The Name variable passed to the Prefix is declared in the base class and will be set when the component is declared within the Machine Module.

The call to the Super^ will create any events contained within the base class as provided by the SPT Base Types Library.

RaiseAlarm2Args

Add a simple method that will be called and passed the alarm that needs to be raised. This will be used by the next method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
METHOD RaiseAlarm2Args
VAR_IN_OUT
    Alarm : FB_TcAlarm;
END_VAR

VAR_INPUT
    (The Name of this component will automatically be applied as a prefix to the message)
    String_Text     : STRING; // First String Parameter 
    String_Suffix   : STRING; // Second String Parameter
END_VAR
-------------------------------------------------------------------------------
F_RaiseAlarmWithStringParameters(Alarm   := Alarm,
                                String_1 := Name,
                                String_2 := String_Text,
                                String_3 := String_Suffix);

Monitoring

Add the Monitoring() method to the component. This method exists within the base class FB_ComponentBase and will be overridden. Within this method the component will monitor the conditions which can Raise an event. Placing this code in the Monitoring() method reduces the complexity of the other methods and provides a single location within the component to locate the condition that raises the event.

Add the following code to the Monitoring method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
IF testVerbose AND NOT ComponentAlarms[E_ComponentEvents.VerboseEvent].bRaised THEN
    RaiseAlarm2Args(Alarm := ComponentAlarms[E_ComponentEvents.VerboseEvent], 'Note_1', 'Note_2');
END_IF

IF testInfo AND NOT ComponentAlarms[E_ComponentEvents.InfoEvent].bRaised THEN
    RaiseAlarm2Args(Alarm := ComponentAlarms[E_ComponentEvents.InfoEvent], 'Note_1', 'Note_2');
END_IF

IF testWarning AND NOT ComponentAlarms[E_ComponentEvents.WarningEvent].bRaised THEN
    RaiseAlarm2Args(Alarm := ComponentAlarms[E_ComponentEvents.WarningEvent], 'Note_1', 'Note_2');
END_IF

IF testError AND NOT ComponentAlarms[E_ComponentEvents.ErrorEvent].bRaised THEN
    RaiseAlarm2Args(Alarm := ComponentAlarms[E_ComponentEvents.ErrorEvent], 'Note_1', 'Note_2');
END_IF

IF testCritical AND NOT ComponentAlarms[E_ComponentEvents.CriticalEvent].bRaised THEN
    RaiseAlarm2Args(Alarm := ComponentAlarms[E_ComponentEvents.CriticalEvent], 'Note_1', 'Note_2');
END_IF

SUPER^.Monitoring();

Each of these test variables were declared earlier in the Component, along with the array of ComponentAlarms. The enumerations used as the array indexes E_ComponentEvent were created from the tmc events. The name ComponentEvents will match the name used within the properties of the event class and not the name of the tmc file.

Checking that the event is not already Raised is one of the steps we take to prevent it from being raised every PLC cycle.

The Note1 and Note2 can be replaced by more specific data. Ideally there would be an event in the tmc file for every possible condition. This would allow for a more flexible solution when implementing language translations. However, it is not always possible to know what these events will be when first creating a component. This is where creating an event of each type (Verbose, Info, Warning, Error, and Critical) can be helpful. This allows you to be able to raise any event type and then provide the details when the event is raised. Even when specific events are added to the tmc, Note 1 and Note 2 can still be used to provide further information about why the event was raised. For example, if a position command is given that exceeds the limits of an axis, these values could be provided, or if a current temperature value is exceeded then the actual and alarm setpoint temperatures can be added using the Notes.

This Monitoring method will be called by the CyclicLogic() method of the base class, from here calling the SUPER^.Monitoring() will call the Monitoring() method of the base class which will raise any alarms within the base class. This is also where the _CurrentEventSeverity is set to Verbose. Therefore, when you add the Monitoring() method to your component it is important to call the Super^, otherwise you will have to reset the _CurrentSeverity within your code. If _CurrentSeverity is never reset to Verbose, then it will retain the highest value it has been set to by the F_GetMaxSeverity function, which can trigger an endless cycle of Raising and Clearing the same alarm, or not being able to clear and alarm at all.

Reset

Add a Reset method that will be called by the Equipment or Machine Module. The reset method will call the function F_ClearAllEventsInClass and the array of ComponentAlarms will be passed into it. This will loop through the array of alarms and if and alarm status is set to Raised, then the Clear method will be called on that alarm. Calling the Super^ will clear the ComponentBaseAlarms. Any actual hardware reset commands for the component should also be done here.

1
2
3
4
5
6
F_ClearAllEventsInClass(Alarms := ComponentAlarms);
IF SUPER^.Reset() THEN
    _Error   := FALSE;
    _ErrorID := 0;
    Reset    := TRUE;
END_IF

Testing the Component Alarms

In the MAIN POU declare an instance of your component and a variable to trigger the Reset() method

1
2
Component : Component := (Name:= 'myComponent');
reset : BOOL;

Call the CyclicLogic() method of the your component, and a way to call the Reset() method

1
2
3
4
5
6
7
    Component.CyclicLogic();

    IF reset THEN
        IF Component.Reset() THEN
            reset := FALSE;
        END_IF
    END_IF

From the Monitoring() method of your component you can now test each alarm and verify that is is raised in the error list. Setting the reset variable to true in MAIN will attempt to clear the alarms. Any alarms that are still set in the Monitoring() method will log both an AlarmCleared and an AlarmRaised, while the ones that are FALSE will simply log AlarmCleared.

Testing Component Alarms