Introduction
While your first program may look complicated at first, it really doesn’t show the power of the AMX programming languages. The program is what we at AMX call “one-to-one.” That means that each button has one and only one function, with no special conditions or considerations. The control panel has a separate section of buttons for each piece of equipment. (See FIG. 1)
FIG. 1 G3 Panel with each button having it’s only one function.
The companion code to this section is called STEP 1a.
PROGRAM_NAME='STEP1'
(* DATE:03/15/02 TIME:12:00:00 *)
(***********************************************************) (* DEVICE NUMBER DEFINITIONS GO BELOW *)
(***********************************************************) DEFINE_DEVICE
RELAY = 5001:8:0 (*NI-3000 RELAY OUTPUTS 1-8 *) VCR = 5001:9:0 (*NI-3000 IR OUTPUT #1*) CD = 5001:10:0 (*NI-3000 IR OUTPUT #2*) CASS = 5001:11:0 (*NI-3000 IR OUTPUT #3*) LIGHTS = 5001:16:0 (*NI-3000 I/O 1-4*) TP = 10128:1:0 (*NXT-CV15 TOUCH PANEL*)
(***********************************************************) (* CONSTANT DEFINITIONS GO BELOW *)
(***********************************************************) DEFINE_CONSTANT
(* TRANSPORT CHANNEL NUMBERS *) PLAY = 1
STOP = 2 PAUSE = 3 FFWD = 4 REW = 5
(* THE RELAY CARD CHANNEL DEFINITIONS *) SCREEN_UP = 1
(* THE LIGHT CARD CHANNEL DEFINITIONS *) LIGHT_FULL = 1
LIGHT_MED = 2 LIGHT_LOW = 3 LIGHT_OFF = 4
(***********************************************************) (* VARIABLE DEFINITIONS GO BELOW *)
(***********************************************************) DEFINE_VARIABLE
(***********************************************************) (* LATCHING DEFINITIONS GO BELOW *)
(***********************************************************) DEFINE_LATCHING
(***********************************************************) (* MUTUALLY EXCLUSIVE DEFINITIONS GO BELOW *)
(***********************************************************) (* STARTUP CODE GOES BELOW *)
Chapter 5 – Conditional Expressions
{
Chapter 5 – Conditional Expressions
PULSE[RELAY,SCREEN_UP]
}
PULSE[RELAY,SCREEN_DOWN]
}
PUSH: (* THE ACTUAL PROGRAM GOES BELOW *)
(***********************************************************)
Chapter 5 – Conditional Expressions
[TP,33] = [RELAY,SCREEN_UP]
[TP,34] = [RELAY,SCREEN_DOWN]
[TP,41] = [RELAY,DRAPE_OPEN]
[TP,42] = [RELAY,DRAPE_CLOSE]
[TP,43] = [RELAY,DRAPE_STOP]
[TP,45] = [LIGHTS,LIGHT_FULL]
[TP,46] = [LIGHTS,LIGHT_MED]
[TP,47] = [LIGHTS,LIGHT_LOW]
[TP,48] = [LIGHTS,LIGHT_OFF]
(***********************************************************) (* END OF PROGRAM *)
(* DO NOT PUT ANY CODE BELOW THIS COMMENT *)
(***********************************************************)
But suppose you want the same number of functions with fewer buttons. A common solution is to have several groups of buttons with similar functions reduced to one group, with a set of buttons that selects which piece of equipment the buttons control. In your program, you could have one button for each piece of equipment to select each deck, and one set of transport buttons. Your panel could now look like FIG. 2:
You now have fewer buttons than you did before. What you want to happen with this panel is that the user selects the deck with a Select button, then controls it with the Transport buttons. This will not be a one-to-one program because the Transport buttons each have three possible functions. In the program you will use conditional expressions to select the correct function of the Transport buttons. Additionally, the System Power has been reduced to one toggling button, which will have its feedback turned on when the system is powered and off when the system is not powered. In other words, one button will perform different functions based on a given condition.
FIG. 2 G3 Panel with multi-functional transport buttons
The companion code to this section is STEP2a
Chapter 5 – Conditional Expressions
Conditional Expressions
A conditional expression is used to tell the system whether or not to execute a particular function or functions in the program. Picture yourself walking along a path in the country. Suddenly you come upon a fork in the road. Which way should you go? If you guess, you might become lost. Therefore you judge certain conditions before continuing. Is the left road heading north? Is the right road heading east?
This is what the Master must do whenever you branch off in different directions in your program.
Either the Master continues in the direction it is going, or it must jump to a different section.
A conditional expression can have one of two results, true or false. In AMX programming, any non-zero value is true and a non-zero value is false. When the Master evaluates a conditional expression, it assigns a 1 for a true result, and a zero for a false result.
The IF Statement
The most common keyword in AMX programming that uses conditional expressions is the IF keyword. Every IF statement must be followed by a conditional expression enclosed in
parentheses. This provides the beginning of a conditional execution of statements. The structure is as follows:
IF(conditional expression) {
Statement 1 }
If the conditional expression is true, the Master executes Statement 1 and then continues with whatever statements follow. If the conditional expression is false, Statement 1 is ignored. The braces indicate that the statement below the condition is a subset. As such, the subset will only be executed if the condition is true.
The IF...ELSE Set of Statements
This is similar to the basic IF statement, with the addition of one more branch. If the conditional expression is false, the Master executes a function independent of the “true” conditional expression.
For example:
IF(conditional expression) {
Statement 1 }
ELSE {
Statement 2 }
If the conditional statement is true, then Statement 1 is executed. Statement 2, underneath the ELSE statement, is ignored. If the conditional statement is false, then Statement 2 is executed. Remember that Statement 1 is automatically ignored if the expression is false.
Repeating IF...ELSE Set of Statements
Using IF... ELSE allows two different paths for conditional branching. By repeating the
IF... ELSE statements multiple paths can be created. The Master will stop conditional evaluation at the first true conditional expression and execute the associated statements. After completion, it goes on to the rest of the program. For example:
IF(Conditional expression)
The last ELSE statement placed at the end of the conditional branching operates as a default statement. That is, if the Master processor does not find a true IF statement, it executes the final ELSE statement. However, the last ELSE statement is not necessary.
Nesting
Once the Master processor is traversing along an IF branch you can tell it to branch off again with another IF statement. This “branch within a branch” is called nesting. An IF can be within an IF within an IF, and so on. The only restriction is the amount of memory available.
When you are nesting IF... ELSE statements, be sure to use braces. Look at the following incorrect example:
Chapter 5 – Conditional Expressions
Even though the alignment suggests the ELSE goes with the first IF, the braces force it to go with the second (nested) IF. The second IF statement is not supposed to have an ELSE counterpart in this example. However, such is not the case. The Master pairs the second IF statement with the ELSE, because both are within the compound statement created by the first and last braces. By rearranging the braces you can force the compiler to associate the ELSE with IF(X = 5). For example:
There is a way to make nesting easier: the SELECT...ACTIVE statement. This allows the easy placement of several branches from one path. Here is the format:
SELECT
Each one of the conditional expressions, in order, is evaluated until one is found to be true. The statements associated with that true expression are then executed, and the path then flows to whatever statements follow the closing brace. So if there are five conditional statements to evaluate and the second one is true, its statements will be executed. The 3rd, 4th and 5th conditional statements will never be checked. The processor will go to the statement following the closing brace of the SELECT...ACTIVE. Using a SELECT...ACTIVE is much preferred to multiple IF...ELSE statements; it uses less memory and it runs faster. If too many IF...ELSE statements are chained together, they can overflow the Master processor memory and crash the
So what happens in a SELECT...ACTIVE if none of the conditions evaluate as true? In such a case, no code of any ACTIVE statement will be executed, since SELECT...ACTIVE has no default statement. You can, however, create your own default for a SELECT...ACTIVE:
SELECT
Here, the last ACTIVE will always be true (remember in AMX programming a 1 is true and a 0 is false), and will execute only if all of the conditions of the previous ACTIVE statements are false.
This makes the last ACTIVE statement the default statement.
Trying it Out
Now you can write the code for your new panel layout. Before you do, however, you will need to update your definition sections a little. The preferred method of implementing “select groups” is to use one variable and change its value based on which deck is selected.
The “Variable Assignment” Method
Assigning different values to one variable depending on what is selected is the preferred method of programming select groups. This method is actually more powerful than other methods, as it provides more flexibility while using a lot less code.
First add just one variable, DECK to the program you wrote previously. This will be the select variable. For a NetLinx Master you will define the variable to contain NetLinx device address information by using the DEV keyword as shown below:
! DEFINE_VARIABLE
! DEV DECK
As we learned early in this manual, there are different types of variables. Meaning that variables can hold different types of data. DEV is one type available to you in Netlinx. A DEV variable can hold the Netlinx device address information in it. Meaning that if we create a variable called DECK of type DEV, DECK will be able to store D:P:S info of any of the devices we declared in the DEFINE_DEVICE section.
Chapter 5 – Conditional Expressions
Based on the code we already wrote in Step 1, DECK would be able to hold the Netlinx address value of RELAY, VCR, CD, CASS, LIGHTS or TP. However, we don't want to hold all of these, we just want to differentiate between which deck we are currently choosing to control.
The code below allows us to use certain buttons to change the value of DECK. Notice there is no way to make DECK equal to TP. Even though our DEV variable can hold that information, that is not what we want. We only want to be able to switch between the VCR, CD or CASS. That is done by using the Device Select buttons on FIG. 2 on page 32 and the code written just below:
BUTTON_EVENT[TP,1]
{ PUSH:
{
DECK=VCR }
}
BUTTON_EVENT[TP,2]
{
PUSH:
{
DECK=CD }
}
BUTTON_EVENT[TP,3]
{
PUSH:
{
DECK=CASS }
}
You can reduce the number of transport sections from three to just one by using the variable DECK
Notice that no IF statement and no mutually exclusive variables are necessary for the variable DECK, and this is the only deck transport section of programming needed in the whole program! But how does this work? Suppose you want to play the CD player. First you press the CD Select button.
This assigns the value 5001:10:0 (the constant value of CD device) to the variable DECK. Now the device-channel references of the PULSE transport statements will reference device number 5001:10:0 (the CD device). Pressing button number 17 on the Touch Panel will activate [DECK,PLAY], which the Master will interpret as [5001:10:0,1].
The feedback for the transport section works in the same manner as the control section. The feedback statements use the DECK variable as the device from which to get the feedback. These statements for the selection buttons, however, are something new:
[TP,1] = (DECK=VCR) [TP,2] = (DECK=CD) [TP,3] = (DECK=CASS)
Chapter 5 – Conditional Expressions
These statements, like all feedback statements, are direct assignment output changes; however, the source of the assignment is a conditional expression. In interpreting this kind of feedback
statement, the master first evaluates the conditional expression. If the expression is evaluated as true, the expression is replaced with a 1; otherwise it is replaced with a zero. (Remember, only one of these will be evaluated as true because a variable cannot have two different values at one time.) Thus the direct assignment will assign a 1 (”on”) to the Touch Panel button for which the
expression is true, and a zero (”off”) to the false ones. Recall that assigning a 1 to a device-channel is the same as turning the output of a device-channel on
Conditional Operators
The previously discussed IF and IF...ELSE statements can only base the program flow on one condition. You can, however, combine two of these conditions with a conditional operator. This operator sets the rules for determining the end result.
The conditional operators used in AMX systems are AND, OR, XOR, and NOT. These are placed in between the two conditions after the IF statement. For example:
IF((X = 10) AND (Y = 5)) {
Statement 1 }
For this condition to be met, 2 things have to be true. X must be equal to 10 and Y must be equal to 5. If the end result of the conditional expression is true, the system continues with Statement 1. If the end result is false, the system simply ignores Statement 1.
In most conditional expressions, the possible conditions of two statements are analyzed to achieve one result. A text formula can be followed to find that result:
""If <condition 1 (true/false)> <conditional operator> <condition 2 (true/false)>, then the result of the expression is true or false."
The result is found by basing the conditions of the statements against the rules set by the conditional operator. Here are those specific rules:
AND Both statements must be true for the result to be true.
OR At least one of the conditions must be true for the result to be true.
XOR Only one statement can be true for the result to be true.
NOT If the statement is true, the result is false. On the contrary, if the condition is false, the result is true. This expression uses only one statement.
Consider the following IF statement:
IF((NUM1 = 5) AND (NUM2 = 4))
Assume that it has been previously defined that NUM1 = 5 and NUM2 = 3. Insert the variables from the example into the text formula:
”If NUM1 = 5 is true and NUM2 = 4 is false, then the result of the expression is false.”
The statement would have been true if NUM2 had been equal to 3, because in an AND expression both statements must be true.
We can use the NOT operator to allow us to program the single power button on this touch panel layout. Since the state of an output channel can be on (1) or off (0), using the NOT operator on a device channel will change its state from off to on or on to off. The code for this button is shown below:
BUTTON_EVENT[TP,31]
{
PUSH:
{
[RELAY,SYS_POWER] = NOT[RELAY,SYS_POWER]
} }
Each press of the button will toggle the state of the SYS_POWER relay. If we did not use the NOT operator to toggle the state, of SYS_POWER we would have to write out the conditional evaluations and each action separately. The code below does the same thing without the NOT operator. Notice the extra lines of code required.
BUTTON_EVENT[TP,31]
The feedback for this button will track the state of the relay channel:
[TP,31] = [RELAY,SYS_POWER]
This would work with either method of code above.
The conditional operators can be abbreviated in your program as shown below:
Conditional Operator Abbreviations
Abbreviation Function Abbreviation Function
&& Logical AND & Bitwise AND
|| Logical OR | Bitwise OR
^^ Logical XOR ^ Bitwise XOR
! Logical NOT ~ Bitwise NOT