Skip to content

Monitoring Alarms

This section is a continuation of the principles covered in SPT Framework Alarms section above.

The supervisory monitoring, response, and clearing of alarms within components and modules requires some configuration to ensure that the alarms are not raised and cleared cyclically, which results in flooding the event logger, and potentially causing other ADS traffic to stop. The below sections will cover how to properly monitor and reset the alarms properly.

Monitoring Components of an EM

While a component will monitor its own conditions for raising an alarm, the EM that contains the component will monitor the component and raise an alarm of its own, indicating the condition. The EM has a default set of responses for the 5 levels of alarms, which can be modified in order to invoke the desired response of the state machine for the EM. The MM will then monitor the EM and respond accordingly.

The CyclicLogic() method of the EM will call the SUPER^.CyclicLogic() which in turn will call the ComponentMonitor() method. Depending on the current state of the EM, this method will loop through all the components and check if any of them have an alarm. An enumeration of Alarm Responses exists which corresponds to the 5 alarm levels.

Here are the defaults:

1
2
3
4
5
6
TcEventSeverity     Alarm Response
Verbose             E_AlarmResponse.NoResponse
Info                E_AlarmResponse.NoResponse
Warning             E_AlarmResponse.NoResponse
Error               E_AlarmResponse.Abort_ImmediateError
Critical            E_AlarmResponse.Abort_ImmediateError

These defaults are initialized to the array variable _ParentFaultResponseDefinitions in the declaration of FB_ComponentBase. When other responses are required the values of _ParentFaultResponseDefinitions can be modified in your code.

1
2
3
4
5
6
    _ParentFaultResponseDefinitions : ARRAY[0..4] OF E_AlarmResponse :=[
        E_AlarmResponse.NoResponse,
        E_AlarmResponse.NoResponse,
        E_AlarmResponse.NoResponse,
        E_AlarmResponse.Abort_ImmediateError,
        E_AlarmResponse.Abort_ImmediateError];

In the ComponentMonitor() method of the EM, the components ParentFaultResponseDefinitions are copied to a local variable AlarmResponses.

1
2
3
4
5
6
7
8
9
    AlarmResponses := ipComponents[i].ParentResponseDefinitions;

    CASE AlarmResponses[ipComponents[i].CurrentAlarmSeverity] OF

                E_AlarmResponse.Abort_ImmediateError:
                    AbortImmediateError(ipComponents[i].Name, FALSE);

                E_AlarmResponse.NoResponse:
                    ;

We then evaluate the components CurrentAlarmSeverity ranging from 0..4, then we evaluate the AlarmResponses array at that index to determine which method to call. So if the CurrentAlarmSeverity is 0 (TcEventSeverity.Verbose) then the AlarmResponse[TcEventSeverity.Verbose] will be E_AlarmResponse.NoResponse. However; if the CurrentAlarmSeverity is 4 (TcEventSeverity.Critical), the AlarmResponse[TcEventSeverity.Critical] will be E_AlarmResponse.Abort_ImmediateError.

Here is another list of the possible Alarm Responses and the method that will be called:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    E_AlarmResponse.        Method Call         
    Abort_ImmediateError    AbortImmediateError()   //Raise Alarm and Change State Abort
    Abort_Immediate         AbortImmediate()        //Change State Abort
    Stop_Immediate          StopImmediate()         //Change State Stop
    Stop_Controlled         StopControlled()        //Change State Stop
    Hold_Immediate          HoldImmediate()         //Change State Hold
    Hold_Controlled         HoldControlled()        //Change State Hold
    Suspend_Immediate       SuspendImmediate()      //Change State Suspend
    Suspend_Controlled      SuspendControlled()     //Change State Suspend
    NoResponse              ;                       //Do Nothing

The code in these methods can be overridden with your own implementation. It is important to remember that there are only 5 Alarm levels and therefore 5 Alarm responses that can be used per EM.

Monitoring Events of the MM

The Machine Module will call it's own ComponentMonitor and SubModuleMonitor methods from CyclicLogic(). However it is possible for the Machine to have its own events that can be monitored in CyclicLogic(). When done properly, if any of these raise an event, the _CurrentAlarmSeverity will be set accordingly. For an Equipment Module the Machine Module will be monitoring this variable through the SubModuleMonitor() method, which is called by CyclicLogic(). However their is no code to monitor and respond to the _CurrentAlarmSeverity() of the Machine Module. Therefore we can use the code within SubModuleMonitor() and modify it to suit our needs. The biggest difference being that the SubModuleMonitor() will loop through all registered SubModules, while the Machine Module only needs to monitor itself.

If you have been following along from the beginning we do not yet have a Machine Module. If you are working in your own project then skip ahead

Create a new Function Block for the Machine Module

1
2
3
4
    FUNCTION_BLOCK Machine EXTENDS FB_PackML_BaseModule
    VAR
        Component : Component := (Name := 'myMachineComponent');
    END_VAR
Add the CyclicLogic() method
1
2
3
4
5
6
7
8
    METHOD PUBLIC CyclicLogic

    IF NOT _InitComplete THEN
        _InitComplete := Initialize();
        RETURN;
    END_IF

    SUPER^.CyclicLogic();
Add the Initialize() method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    METHOD PROTECTED Initialize : BOOL

    Initialize := FALSE;
    CASE DescendantSequenceState OF
        0:
            RegisterComponent(Component);
            DescendantSequenceState := DescendantSequenceState + 10;

        10:
            IF SUPER^.Initialize() THEN
                Initialize := TRUE;
            END_IF
    END_CASE

Create a new method named MachineMonitor()

1
2
3
4
    METHOD MachineMonitor
    VAR
        AlarmResponses : ARRAY[0..4] OF E_AlarmResponse; //Temporary response array 
    END_VAR

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    IF _CurrentState <> E_PMLState.ePMLState_Aborted 
        AND _CurrentState <> E_PMLState.ePMLState_Aborting 
        AND _CurrentState <> E_PMLState.ePMLState_Clearing 
        AND _CurrentState <> E_PMLState.ePMLState_Stopped 
        AND _CurrentState <> E_PMLState.ePMLState_Stopping THEN

        AlarmResponses := ParentResponseDefinitions;

        CASE AlarmResponses[_CurrentAlarmSeverity] OF
            E_AlarmResponse.Abort_ImmediateError:
                AbortImmediateError(Name, TRUE);

            E_AlarmResponse.Abort_Immediate:
                AbortImmediate();

            E_AlarmResponse.Stop_Immediate:
                StopImmediate();

            E_AlarmResponse.Stop_Controlled:
                StopControlled();

            E_AlarmResponse.Hold_Immediate:
                HoldImmediate();

            E_AlarmResponse.Hold_Controlled:
                HoldControlled();

            E_AlarmResponse.Suspend_Immediate:
                SuspendImmediate();

            E_AlarmResponse.Suspend_Controlled:
                SuspendControlled();

            E_AlarmResponse.NoResponse:
                ;
        END_CASE
    ELSIF _CurrentState = E_PMLState.ePMLState_Stopped 
            OR _CurrentState = E_PMLState.ePMLState_Stopping THEN

        AlarmResponses := ParentResponseDefinitions;

        CASE AlarmResponses[CurrentAlarmSeverity] OF
            E_AlarmResponse.Abort_ImmediateError:
                AbortImmediateError(Name, TRUE);

            E_AlarmResponse.Abort_Immediate:
                AbortImmediate();

            E_AlarmResponse.NoResponse:
                ;
        END_CASE
    END_IF
Open CyclicLogic and call MachineMonitor() before SUPER^.CyclicLogic()

Then _Error after SUPER^.CyclicLogic()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    //The MachineMonitor is based on the SubModuleMonitor, but is only monitors itself
    MachineMonitor();

    //
    SUPER^.CyclicLogic();

    (*
    // Code must be after SUPER^.CyclicLogic();
    *)

    // The TcEventSeverity of each Submodule and Component will increase the 
    // _CurrentAlarmSeverity during the call to SUPER^.CyclicLogic().
    // We then set the local _Error bit based on this

    _Error := _CurrentAlarmSeverity >= TcEventSeverity.Error;