Control Solutions is your source for LonWorks I/O.
Tutorial #2

Variables and Arrays

Variables may be declared in the "declare" block of a program or procedure, and must appear after named type declarations. The general syntax for a variable declaration is:

<name> : <type>;
<name> : array [<a>..<b>] of <type>;

The <name> may be any name starting with a letter, and containing only letters or digits or underscore after the first letter. Names are case sensitive. If an array is specified, the starting and ending subscripts <a> and <b> must be specified, and <b> must be greater than <a> (and both must be literal numbers).

The <type> may be any valid simple type from the table below, or any previously declared named type including record types. Refer to examples that follow for an illustration of several variable declarations including simple, array, and named array of records.

Variables declared inside a procedure are referred to as "local" variables. These local variables exist only for the duration of the procedure, and are only accessible to that procedure. Local variables are created when the procedure is called, and destroyed upon exit from the procedure. Only global variables declared at the very beginning of the program will exist indefinitely.

The following example illustrates use of two global variables.

program verySimple
declare
myIntVar: int;
myFloatVar: float;

begin
myIntVar = 10;
myFloatVar = 10.125;
end

The following example illustrates use of both a global variable and a local variable. The variable named "led" is local, and exists only for the duration of execution of the procedure.

program dimmer
declare
ivar: int;

procedure turnon (bright: int)
declare
led: int;
begin
led = bright * 10;
seti (19, led);
delay (5);
end;

begin
while TRUE do
begin
for ivar = 0 to 20 turnon(ivar);
for ivar = 20 down to 0 turnon(ivar);
end;
end

Data Types

Named data types may be declared in the "declare" block of a program or procedure, and must appear before any actual variables are declared. The general syntax for a named type declaration is:

type <name> = <type>;
type <name> = array [<a>..<b>] of <type>;

The <name> may be any name starting with a letter, and containing only letters or digits or underscore after the first letter. Names are case sensitive. If an array is specified, the starting and ending subscripts <a> and <b> must be specified, and <b> must be greater than <a> (and both must be literal numbers).

program tryThis
declare
type bunchOfBytes = array[1..10] of uint8;
myBytes: bunchOfBytes;

begin
myBytes[1] = 10;
myBytes[2] = 15;
myBytes[3] = 25;
end

The <type> may be any valid simple type, or may be a record declaration with a field list. Types recognized by PL/i are listed below. Be sure to observe the note about type casting under Assignment Statement further down.

int
Integer stored as 32-bit signed integer
float
IEEE 754 floating point, 32-bit format
int16
Integer stored as 16-bit signed integer
uint16
Integer stored as 16-bit unsigned integer
int8
Integer stored as 8-bit signed integer
uint8
Integer stored as 8-bit unsigned integer
boolean
Boolean having a value of 0 or 1, stored as 8-bit unsigned integer
bit
Bit having a value of 0 or 1, same as boolean if variable,
packed into 8-bit groups if record field
record
Byte packed list of fields comprised of above types (see below)

Note that 8 bits are stored as 8 bytes when declared as independent variables, but 8 bits will be stored in a single byte when they are fields within a record. It should also be noted that integer values less than 32 bits are processed internally as interim 32-bit data values and truncated only when stored to declared variables. Therefore, the following combination is a legal bounds check:

program test
declare
myVar: uint16;
result: uint16;

begin
myVar = geti (100);
if int(myVar) * 10 > 65535 then result = 65535;
else result = int(myVar) * 10;
endif;
end

An important note about type casting: Variables may be any of the types noted above. However, math functions only operate on integer or floating point. If you mix types such as uint8, int16, etc., in a mathematical expression, you will get an "Unexpected types in assignment" error message. Any time you wish to assign a variable to a different type of variable, or do math with anything other then integer or floating point, you must first convert the data to "int" or "float" using the int and float functions.

In the following example, the first four assignment statements will work, but the last one will cause an "Unexpected types" error. The target of the assignment may be any type, but the operands of the expression must be integer or floating point.

program test
declare
thisVar: uint8;
thatVar: int;
otherVar: float;

begin
thisVar = thatVar;
thisVar = otherVar;
thatVar = int(thisVar);
otherVar = float(thisVar);
thatVar = thisVar; // WRONG!
end

What's wrong with the last instance? The operand is not "int" or "float". Either "int" or "float" may be assigned to any type variable. Any other type variable may not be an operand (thus may not be assigned to another variable).

Constants and Numeric Literals

Definitions of constants live only for the life of the program compile process, after which they become hard coded into the program wherever used. They are intended to enhance program readability and maintainability through parameterization of things like register numbers. The syntax for a constant definition is:

# <name> = <integer>;

The <integer> must be an integer numeric literal. The intended primary use of constants is "naming" of registers within the program. Floating point constants are not currently supported. An example of intended use of constants follows:

program dimmer
declare

#Room225 = 1001;
#FanDrive = 25;
RoomTemp: float;

begin
RoomTemp = getf (#Room225);
if RoomTemp > 82.5 then
seti (#FanDrive, 1);
endif;
end

Numeric literals may be integer or floating point, and the data type does matter in many instances. If the numeric string contains a decimal point, it will be interpreted as floating point. If not, it will be assigned as integer. Examples of literals:

1is an integer
1.0is the exact same value, but applied as a floating point number

For convenience, the literals TRUE and FALSE are predefined as 1 and 0. Both of these are defined as all upper case, and return a type of boolean.

Records

Record declaration syntax is as follows:

type <name> = record <field list> end;

Each element of the field list will follow the same syntax as a variable declaration. Refer to example below for an illustration of a record declaration. Elements of the record are identified by name, and are treated as any other variable for purposes of rules of the language.

program test
declare
type myRec = record
ival1: int;
ival2: int;
bval1: bit;
bval2: bit;
fval1: float;
fval2: float;
end;

type myRecordSet = array [1..20] of myRec;
myVar: myRecordSet;

begin
myVar[4].ival1 = 10;
myVar[4].bval1 = 1;
myVar[4].fval1 = 2.585;
end