6.2   The Triggering GUI

To work with triggering, click the button in the main tool bar. This brings up the Triggering window, shown in Figure 6-1. The Triggering window allows you to define, modify, download, and control triggers. Until you set one or more triggers, the window displays only the legend "None." Even after you have defined a trigger, it appears as "not set." You must download it to the target before it is armed and ready to fire.   

To define a trigger, click the button at the left of the Triggering tool bar. This brings up the Trigger Maintenance dialog box, shown in Figure 6-2. When you open the Trigger Maintenance dialog box, the next available trigger number is shown in the first field.      

Specifying a Trigger

In most cases you should leave the Enabled box checked. If you are going to chain this trigger and have it enabled by an earlier trigger or if you are going to start it from your code, uncheck this box. The remaining specification boxes allow you to narrow the circumstances under which your trigger will fire.

You can specify the type of event or a user event by selecting it from the Event Matches drop-down menu. If you chose User Event, the right hand field becomes active so you can enter the name of the user event. This user event is one you create using the trgEvent( ) routine. (See the reference entry for trgEvent( ) in C. Library and Subroutine Reference. For an example that uses trgEvent( ), see Example 6-6.)

You can cause your trigger to fire on an event that occurs in any context, any task, a specific task, any ISR (interrupt service routine), or the system context. If you choose Specific Task from the Context Matches drop-down menu, you must fill in the task name in the right-hand field. If you choose Specific Object from the Object Matches drop-down menu, you must enter the object ID in the right-hand field.

At each potential triggering point, tests are performed to see if the criteria you have specified for event, context, and object conditions have been met. If they have, triggering proceeds to evaluate any additional criteria you may have set.

You can make your trigger conditional upon a variable or function taking a specific value or range of values. Change (unconditionally) to conditional upon and select Var (variable) or Fn (function) from the drop-down menu. Enter the variable or function name, select the matching criterion from the drop-down menu (==, <=, and so on), and enter the value to test in the last field.

Testing a Variable

In order to fire your trigger when a variable takes a specified value, you must specify the following:

where:

<operand 1>
is a known, 32-bit identifier on the target (for example, foo)

operator
is selected from the drop down list (==, >=, <)

<operand 2>
is a 32-bit integer constant in either decimal or hexadecimal format (for example, 0x13579bde)


*

WARNING: The value to test, <operand 2>, must be an integer.

Testing a Function

In order to fire your trigger when a function takes a specified value, you must provide a function on the target which will be executed if all of the criteria specified for event, context, and object conditions have been met. Both the format and content of the function provided are important for correct operation.

The conditional function provided must be of the form

int  condFunc (void) 
    { 
    int returnValue; 
 
    /* 
     * Function body. Must contain only code that can be executed in ISR 
     * context. See VxWorks Programmer's Guide: Basic OS  
     * Use of logMsg() and printf() are also prohibited. 
     */ 
 
    ... 
 
    return (returnValue); 
    }


*

NOTE: The body of the function provided can contain any code desired, but must not contain any function calls which are not permitted in Interrupt Service Routine (ISR) context. This is because, depending on the criteria specified for event, context, and object conditions, the function provided may well be executed within an ISR.


*

WARNING: The return value, <operand 2>, must be an integer.

Having provided a valid conditional function, it should be compiled for the target architecture and the resulting object module loaded onto the target. For example, if a function condFunc( ) is contained in a C module called condFunc.c and compiled into an object module condFunc.o, the object module can be loaded on to the target from a Tornado shell using the following command:

% ld < condFunc.o

If your function returns 1 under the conditions where you want your trigger to fire, you would specify the following:   

Here, <operand 1> is treated as a function name and <operand 2> is treated as a 32-bit integer constant.


*

NOTE: There is a major difference between the function used as a condition and the function used as a trigger action. The function used as a condition is executed, in line, during trigger evaluation, provided that the criteria for event, context, and object conditions have been satisfied. Unlike a trigger action function, a conditional function can not be deferred. You can check the Safe box for an action function to assure that it will not run within ISR or system context (see Specifying an Action). There is no Safe option for conditional functions, so you must write or call a function that can be safely executed within an ISR or system context.

For example, the following conditional function is invalid:

int condFunc (void) 
    { 
    if (vxTicks >= (sysClkRateGet() * 60 * 60)) 
        { 
        semTake (mySem);        /* semTake NOT ALLOWED in ISR context*/ 
        printf ("The system has been up for more than an hour\n");   
                                /* printf NOT ALLOWED in ISR context*/ 
        return 1; 
        } 
    return 0; 
    }

This is because semTake( ) must not be used in an ISR. In addition, due to the fact that trigger evaluation points are present throughout the VxWorks kernel, you can not use printf( ) or logMsg( ) in condition functions. (For information about which routines can safely be called from ISRs, see the VxWorks Programmer's Guide: Basic OS.) This example could be corrected by making the printf( ) into a trigger action function and making it Safe to achieve the same result (see Example 6-7).


*

NOTE: There is one exception to the rule that you can not use any function that may not be called from an ISR. If the combination of trigger qualifications set in the event, context, and object fields guarantees that they can only all be satisfied in task context (for example, by setting Context Matches to Any Task or Specific Task). If this is the case, the condition function itself will only ever be executed in task context and can therefore contain anything you like.

Specifying an Action

The bottom section of the Trigger Maintenance dialog box allows you to specify what happens when your trigger fires. You can select (no action), Start WV, Stop WV, or Call function. If you select Call function, the right two fields become active. Fill in the function name in the first field and an integer argument in the second field.

When selecting an action function for a trigger, the nature of the function to be called is important. It should be of the form:

int actionFunc (int arg) 
    { 
    int returnValue; 
 
    /* function body */ 
    return (returnValue); 
    }

The entry in the Action section of the Trigger Maintenance dialog box is of the form:

where:

<function>
is the name of the function to be called (actionFunc( ) in the above example)

<fn argument>
is an integer argument

If the function contains calls to any function that is not permitted in ISR context, then the Safe box must be checked. (This is the default.) In this case, the function is not executed at the time when trigger evaluation is performed and found to be satisfied; instead it is added to a trigger work queue. Triggering automatically spawns a task called tActDef whose responsibility it is to execute functions on the trigger work queue when the system is out of any critical region. If your application runs at a higher priority than tActDef, you may have to adjust the priority if you want the trigger action to be executed.

The last item you can specify is what happens after the trigger fires. You may disable this trigger once it fires (the default), or allow it to remain active so that it will fire again if the conditions are met again. You can also chain another trigger to it, which is enabled when the first trigger fires. You must specify the second trigger by number, so you need to define it before you can select it from the drop-down menu.

Saving a Trigger Configuration

Once you have created a trigger configuration, you can save it to a file. This allows you to repeat a precise sequence and can be useful in troubleshooting. Click the ( ) button and use the File Save dialog box to choose a directory and file name for your configuration.

Loading a Trigger Configuration File

A saved trigger configuration can be loaded using the button. Load the sample file installDir/host/src/windview/samples/simpleCond.trg by clicking the button and selecting it in the browse menu. Once this trigger has loaded, the Triggering window looks just like Figure 6-1; the window no longer says "None", but the trigger is not yet set.

Before you start triggering, you can review the trigger configuration you have loaded. Click on the button and select Trigger # 0 from the drop-down combo box. This displays the trigger specification and action that you loaded. (See Figure 6-4.) You can see that this sample trigger fires when variable foo takes the value 1. When that condition is met, printf( ) is called with the value helloString.

Starting Triggering

Once you have created your triggers, either by filling in the Trigger Maintenance dialog box or by loading a trigger configuration file, they must be compiled and downloaded to the target. Clicking the button compiles and downloads your trigger. The Target ID changes from "not set" to a hexadecimal ID number and the status is "Armed." (See Figure 6-3).   

Stopping Triggering

Click the button to stop triggering. Your triggers still remain on the target but the code is not executed.


*

NOTE: When you click to restart triggering, whatever configuration is currently in place on the host is downloaded and started. Even if it is the same configuration you loaded previously, all triggers are reset as they were initially. Execution does not continue from where it was when you stopped triggering.

Chaining Triggers

Chaining triggers provides a way to be sure of the order in which your triggers will fire. For instance, to use triggering to collect a WindView log you must define two triggers, one having the action to start WindView log collection and one with the action to stop WindView log collection. In most cases, these triggers are chained since the order of their firing is critical.

To chain triggers, define both triggers using the Trigger Maintenance dialog box. After defining both triggers, open the first one in the Trigger Maintenance dialog box and select the name of the second trigger in the last drop-down combo box.

Triggering provides a powerful mechanism for isolating the sequence that you wish WindView to capture for later analysis. If you can define two triggers to enclose the precise region of interest in your application, you can make the best use of both your system resources and your own time spent in analysis.