• No results found

Arrays and Strings

In document Amx Netlinx Programming Ba01 (Page 62-74)

Introduction

In the previous units you developed a program that demonstrates the most common features of the AMX programming languages. In this unit, more advanced concepts will be introduced: arrays, strings, buffers, and two-dimensional arrays. Understanding these concepts and the keywords that go with them will allow you to easily handle data, and will provide another means of

communicating with the outside world.

In this chapter, you will develop a small example program. For this program, you will need to create a level and assign it to a variable. You will use the variable VOLUME_LEVEL for this. Your control panel will have nine buttons: Volume Up (button 1), Volume Down (button 2), Store (button 3), Preset 1, Preset 2, Preset 3, Preset 4, Preset 5, and Preset 6 (buttons 9 through 14). The Volume Up and Volume Down buttons ramp a volume card up and down. The Store button simply toggles a state on and off. The Preset 1–6 buttons either store or recall a preset, depending on whether the Store button is on or not.

Defining Arrays

In the program developed in Unit 2, you used a variable called DECK. This variable could only hold one value at a time. However, if you need a variable to hold several values at once, use an array. An array is a single variable that has more than one storage location.

Arrays must be defined as variables within the DEFINE_VARIABLE section of your program. Its definition has two parts: a unique identifier and its storage capacity. The variable must be named using a valid identifier first. (See Identifiers on page 6 for the rules concerning identifiers).

Second, the number of storage locations in the array must be indicated; a maximum of 65535 locations for NetLinx systems. For your new program, you want to store several preset levels for the volume control device. You could create several individual variables and use IF statements or SELECT...ACTIVE statements to select the preset you want to use. Or even better, you could create an array and use an index value to pick the preset you want to use. Here is the array declaration:

DEFINE_VARIABLE PRESETS[6]

The companion code to this section is STEP5a.

This declares a new variable, PRESETS. The variable PRESETS is an array that can hold six distinct values, as defined by the number 6 inside the brackets.

Accessing and Storing Array Values

To access a particular value in an array, simply refer to the storage location inside the array you wish to read, such as follows:

THE_LEVEL=PRESETS[3]

The number inside the brackets is called the index value. The index value is the number that tells the master which location in the array to read. In this example it is a number from 1 to 255. It also assigns the value in the third location of PRESETS to the variable THE_LEVEL. Reading a value from an array does not in any change the array.

You can place values into a storage location by setting the particular location equal to the needed value. For example, PRESETS was previously defined as having six locations. If you want the second location to hold a value of 6 you would type the following:

PRESETS[2]=6

The number 6 is placed into the second location. From now on, anytime PRESETS[2] is referenced, its value is 6.

Chapter 8 – Arrays and Strings

In this program, pressing a Preset button either stores or recalls a preset. Examine the section of code that accomplishes this:

BUTTON_EVENT [TP, 3] // PRESET VOLUME BUTTON (STORE / RECALL) {

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [1]) //SEND PRESET 1

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [2]) //SEND PRESET 2

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [3]) //SEND PRESET 3

} } }

BUTTON EVENT [TP, 12] // PRESET NUMBER 4

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [4]) //SEND PRESET 4

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [5]) //SEND PRESET 5

SEND_COMMMAND VOLUME, "'P0L',ITOA (PRESETS [6]) //SEND PRESET 6

} } }

DEFINE_PROGRAM

[TP,3]=STORE //TURN ON BUTTON WHEN STORE MODE IS ON

Chapter 8 – Arrays and Strings

The BUTTON_EVENT [TP, 3] is the Store button, which simply toggles the STORE variable using the NOT operator.

Next, there is a button event written for each of the 6 preset buttons. Each button events works the same way. When the button is pushed, the processor checks to see if the variable STORE is true or false (on or off). If it is true (on), then the current volume level is stored in that preset position. If STORE is not true (off), then a command is sent to the device VOLUME to recall the VOLUME_LEVEL value that is currently stored in that preset position. Each of these events works the same way. The only difference is which preset is being manipulated.

Our array PRESET has a size of [6]. This means that is can store 6 values. Since we have six preset buttons we associate each one with a different position of the array. These positions are referred to as elements. So BUTTON_EVENT [TP, 9] handles PRESET [1], BUTTON_EVENT [TP, 10]

handles PRESET [2], BUTTON_EVENT [TP, 11] handles PRESET [3] and so on.

Next, we check to see if the STORE mode is on. If STORE is on, we assign the appropriate location in the PRESETS array to the current volume level. If STORE is off, we send a command to the volume card telling it to go to the previously stored level.

Data Types

When dealing with data, we often refer to "equivalents". With ASCII characters, we often refer to the ASCII table that shows the ASCII character, Decimal equivalent, and Hexadecimal (Hex) equivalent. The complete chart is on page 79 of this manual. It is important to understand that these values really are interchangeable within your program. This provides you the flexibility of using the most appropriate or convenient data type for each specific application. Further, it is extremely important to understand that the machine code that actually runs in the Master after compilation, is binary-1s and 0s. Each of the other data types we discuss are really equivalents of the underlying binary value.

A simple way to communicate this data equivalent issue is to take the word 'HELLO' and break it down into other data types. We'll use a mix of ASCII, Decimal, and Hex to create an equivalent expression, then convert the entire thing to binary to see what the Master actually evaluates in the compiled code. From the ASCII table, we look at each character:

Remember, NOT inverts the state of whatever follows it.

ASCII Decimal Hex

H

E 72

L 4C

L 76

O 4F

So the ASCII string literal 'HELLO' can also be expressed as a string expression

"'H',72,$4C,76,$4F".

Once this code is compiled, the Master would actually be evaluating binary values like this:

0100111101000101010011000100110001001111. We don't actually have a binary data type, so this is just presented to you for your information. In future programming classes, you'll learn more about working with binary values in a topic called "Bitwise Manipulation".

As you move forward through this manual, you will encounter various mentions of ASCII, decimal and Hexadecimal values. Please keep this fundamental data type discussion in mind as you proceed.

Strings

Many times you may need to reference entire groups of values at once. You can do this by using strings and string expressions. A string is a set of values grouped together with single and/or double quotes. Strings enclosed in single quotes are called string literals -values from the ASCII table ranging from decimal 32 (the space character) to decimal 126 (the tilde '~' character). An expression is surrounded by double quotes, and may contain a combination of string literals, decimal values and hexadecimal values.

Strings may be used in our control program as constants or variables. Constants are values or strings that are set at compile time and will not change throughout the life of the program. Variables are values or strings that may be initialized at compile time, but are expected to change as the program runs. Here is an example of assigning a string to an array (either constant or variable):

FAVORITE = 'ESPN'

When the Master processes this assignment, it places the ASCII character 'E' (decimal value 69) in location 1 of FAVORITE, ASCII character 'S' (decimal value 83) in location 2, and so on. String 'ESPN' is placed in the array FAVORITE. Note that an index value is not given when strings are assigned to arrays. The first letter is automatically placed into the first storage location; the second letter is placed into the second storage location; and so on. In this example, the array FAVORITE would have to have a size of at least 4 when defined. The definition might look like this:

DEFINE_VARIABLE CHAR FAVORITE [4]

AMX uses the $ symbol to indicate the use of Hex values.

Chapter 8 – Arrays and Strings

The String Expression

AMX Control System Masters interpret single and double quotes in two different ways. Whereas single quotes enclose string literals, double quotes represent a different operation: they enclose string expressions. A string expression combines several types of data into a single string. A string expression can contain any ASCII value (0 to 255), as well as constants, variables, string literals, and arrays. As the Master processes a string expression, it evaluates each member of the expression from left to right, and the result is a complete string. Here is an example:

EXPRESSION="PLAY,5,0,'NO',X,$0D"

Assuming that PLAY is a constant previously defined with the value of 1, and X is a variable with the current value of 10, the string expression is evaluated as a string with the following values:

1,5,0,N,O,10 and carriage return (Hex 0D). Since the expression is evaluated at run time, whatever value is in the variable X when the expression is evaluated is what is placed into the result.

String Elements

There are two ways of referencing data in arrays within AMX programming code: each location within an array as an individual value, or each array as a group of values. So far you have seen how to reference an entire string. However, each element of a string can also be accessed as individual characters. If you refer to an array and specify an index value, the contents of that specific element will be loaded or returned. Consider the following lines:

DEFINE_VARIABLE

S1[10] //DECLARE AN ARRAY WITH CAPACITY FOR 10 CHARACTERS CHAR FIRST

CHAR SECOND DEFINE_PROGRAM

S1='TEST ONE' //LOAD CONTENTS INTO THE ARRAY AS A STRING FIRST=S1[1] //THIS VARIABLE GETS THE 1ST ELEMENT OF S1: T SECOND=S1[2] //THIS VARIABLE GETS THE 2ND ELEMENT OF S1: E

This small section of code shows how to read individual elements of an array, by returning them to another variable. In this example, we loaded S1 as a string, but read it's contents out as individual elements. In normal programming, it is recommended that you read data out in the same manner as you load data in. For example, if you load S1 as a string, you would also read it as a string, but if you load it one element at a time, you would read it out as individual elements.

Here is another example. Suppose that during power-up of the control system you want to set all of the presets to default values. You could do this by assigning values to each individual location in the PRESETS array as shown:

DEFINE_START PRESETS[1]=0 PRESETS[2]=30 PRESETS[3]=90 and so on and so on for all 6.

A better solution, however, is to use a string expression to set all six at once, like this:

DEFINE_VARIABLE INTEGER PRESETS[6]=

{

0, 30, 90, 128, 191, 255 // EACH POSITION IN THE ARRAY IS // ASSIGNED A DEFAULT VALUE

}

String Lengths

Every array declared in the DEFINE_VARIABLE section has a string length value associated with it.

The string length of an array indicates the actual contents of the array as by string assignment operations. This number is different than the storage capacity declared in the DEFINE_VARIABLE section. You can get this length value of an array by using the LENGTH_STRING function. Here is an example:

Y = LENGTH_STRING(PRESETS)

Here are examples of some assignments, and what the above line of code would return to the variable Y in each case:

PRESETS = 'FOUR' (* Y = 4 *) PRESETS = 'ONE' (* Y = 3 *)

PRESETS = "12,5,'123'" (* Y = 5 *)

PRESETS = "PLAY,5,0,'NO',X" (* Y = 6 ASSUMING PLAY AND X ARE INTEGERS*) Notice that each character in a string literal is counted separately, but numeric values (decimal or hex) are counted as a single entity. The length of a string array cannot exceed the number of storage locations allocated to it in the DEFINE_VARIABLE section. If the string 'GOODBYE' is placed in the PRESETS variable, the array will only contain the string 'GOODBY,' dropping the final 'E' because PRESETS was defined to hold a maximum of six elements. The length of PRESETS would also be set to 6.

Assigning string literals and string expressions automatically sets the length of the string array to the length of the string literal or string expression being assigned to it. However, assigning values to individual elements of an array does not affect the length value of the array. For instance, if the letters 'W', 'O','R', and 'D' are assigned individually to elements of PRESETS as shown below, the length will not change. If the length was previously 3, it will still be 3.

PRESETS[1] = 'W' PRESETS[2] = 'O' PRESETS[3] = 'R' PRESETS[4] = 'D'

There is a way, however, to explicitly set the string length value of an array variable. The SET_LENGTH_STRING keyword accomplishes this. For instance, to set the length value of PRESETS to 4, you would use the following statement:

SET_LENGTH_STRING(PRESETS,4)

Chapter 8 – Arrays and Strings

After execution, the string length value of the array PRESETS is 4. String lengths play an important role in the handling of strings. Consider this string expression that contains an array in the

expression:

"5,PRESETS,'GO'"

As the Master constructs a string from this string expression, the number of characters from the array PRESETS will be equal to LENGTH_STRING (PRESETS). If PRESETS contains “1,2,3,4,5,6”

but its string length value is 3, the resulting string from the above string expression will look like this:

"5,1,2,3,'G','O'"

The string length value of an array is very important to many string operations in AMX Programming. This value determines how much of the string is used when the entire array is referenced as a string. Knowing this will prevent subtle errors from creeping into your code. For instance, if you assign values to individual elements in an array, and then assign that array to another, nothing will actually be copied. Here is an example:

PRESETS[1] = 5 PRESETS[2] = 6 PRESETS[4] = 'A' SAVE_PRESETS = PRESETS

What do you think the array SAVE_PRESETS will contain after this code is executed? It will totally depend on the length value of the PRESETS variable. If this were the entire program, PRESETS would have a default length of 0, so nothing would be copied into SAVE_PRESETS. In order to assure that SAVE_PRESETS were to hold a copy of PRESETS, you would first need to set the length value of the PRESETS array with this line inserted before the copy statement:

SET_LENGTH_STRING (PRESETS,4)

After this, the length value of PRESETS is 4, so the first 4 locations of PRESETS will be used in all cases where you refer to the entire array.

Sending Strings and Arrays

To send a string to the outside world, you use the SEND_STRING keyword. Here is the syntax:

SEND_STRING device,<string, variable, or string expression>

The first value after the SEND_STRING keyword is the device number or identifier to which you wish to send the string. Following that is a comma, then the string, variable (which can be either a normal variable or an array), or string expression you wish to send. When an array variable is specified, the number of characters from the array that are sent is determined by the length value for the array. (Remember, you can set that value with the SET_LENGTH_STRING function.)

For instance, if you need to send the PRESETS array to a device named RS232, you would write the following line:

SEND_STRING RS232,PRESETS

String literals and string expressions can also be sent using SEND_STRING. Here are some examples:

SEND_STRING RS232,'THIS IS A STRING LITERAL' SEND_STRING RS232,"'EXPRESSION ',PRESETS,$0D,$0A"

The first example sends the entire set of characters enclosed in the single quotes, from left to right, through the port to the device named RS232. The second example first builds the string expression using a string literal, followed by however many characters from PRESETS as defined by its length value, and then two numbers expressed here in hexadecimal. (The hexadecimal numbers in the example represent the codes for “carriage return” and “line feed,” respectively.)

ASCII Codes

As you have learned, a string literal is broken up into single letters when placed into a string array.

Each storage space returns the letter it is holding when referenced. For example, assume that PRESETS[3] holds the letter ‘R.’ There are actually three ways you can reference this array location (in this example using IF statements):

IF(TEMP[3] = 'R') {

(* statement(s) *) }

or

IF(TEMP[3] = 82) {

(* statement(s) *) }

or

IF(TEMP[3] = $52) {

(* statement(s) *) }

The ASCII character ‘R’ has a value of 82 decimal and 52 in hexadecimal. In AMX Programming, hexadecimal numbers begin with a dollar sign ($). Therefore, the third example above shows $52, meaning, “this number, 52, is a hexadecimal number.”

All three methods—letters, decimal ASCII codes, and hexadecimal ASCII codes can be used interchangeably. Feel free to use whichever method is easiest for the task at hand.

Integer Arrays

So far, in all of the arrays you have seen, the valid range of values in each element is 0-255. This is the result of an 8-bit memory allocation for each element; all bits off results in the value 0, and all bits on results in the value 255. If a value greater than 255 is assigned to an array location, the number is truncated by wrapping around back to 0. For instance, if the number 500 is assigned to a location in a character array, the actual number that is assigned is 244. (The way to find this is to keep subtracting 256 from the number until the number is less than 256.)

Chapter 8 – Arrays and Strings

So what could you do if you need to create an array in which each location can contain values greater than 255? The answer is to use an integer array. An integer array is just like a character array, except that each location allocates 16-bits and can hold values from 0-65,535. To declare an integer array, simply place the keyword INTEGER in front of the array definition in the

DEFINE_VARIABLE section. If you wanted your PRESETS array to be an integer array, here is how you would declare it:

DEFINE_VARIABLE INTEGER PRESETS[6]

This declares an integer array with six locations; each location can hold values from 0-65,535.

There are certain limitations of integer arrays. If an integer value above 255 is assigned to a character array, all values are truncated above 255. (See the discussion on truncating values onpage 64.) This also happens if an integer array is sent to a device using the keywords

SEND_STRING or SEND_COMMAND. There is no problem, however, in assigning a normal array to an integer array. If your array is only going to hold only alphanumeric values, do not make it an integer array.

In document Amx Netlinx Programming Ba01 (Page 62-74)

Related documents