Numeric Formats

# Numeric Formats

Numeric (Integer) constants may be expressed in three formats; decimal, hexadecimal, or quoted character.

Decimal constants are specified by writing a decimal number. Hexadecimal constants are specified by prefacing the hex constant by 0x. Quoted character constants are a single character placed between single quotes (') and have the numeric value specified on an ASCII chart.

Examples:

   INTEGER I;

    I=123;   // Specify Decimal constant.

    I=0xABC; // Specify a Hexadecimal constant (Decimal value 2748)

    I='A';   // Specify a character constant (Decimal value 65)

    INTEGER K;

    K=54;    // Specify Decimal constant

    K=0x36;  // Specify a Hexadecimal Constant (Decimal

             // Value 54)

    K='6';   // All three of these are the same value

             // (Decimal value 54)

The three forms may be used interchangeably and are used to make code more readable.

Example:

    STRING A$[10], B$[10], C$[10];

    INTEGER I;

    BUFFER_INPUT COM_IN$[50];

    // A$, B$, and C$ contain identical values

    // after these lines run.

    A$=CHR('A');

    B$=CHR(65);

    C$=CHR(0x41);

    // Preserve the lower nibble of a word, mask the rest out.

    I = VAL1 & 0x000F;

    // Read until a comma is detected in the stream.

    DO

    {

      I = GetC(COM_IN$)

    }

      UNTIL (I = ',');

BUFFER_INPUT CHR Constant DO Formats GetC INTEGER Numeric STRING UNTIL


Operator Precedence & Grouping

# Operator Precedence & Grouping

In an expression where many operators are present, some operators have "priority" over others. Operators with the same precedence level are evaluated strictly left to right. Grouping is used to change the way an expression is evaluated.

Operator Precedence & Grouping

|  |  |
|----|----|
| PRECEDENCE LEVEL | OPERATORS |
| 1 | \- (Negate) |
| 2 | ! NOT |
| 3 | \* / S/ MOD % |
| 4 | \+ - |
| 5 | {{  }} |
| 6 | \<\<  \>\> |
| 7 | \>  \<  \>= \<=  S\>  S\>  S\>=  S\<= |
| 8 | = \<\> |
| 9 | & |
| 10 | ^ |
| 11 | | |
| 12 | && |
| 13 | || |

As an example, the expression:

    3+5\*6

Evaluates to 33 since the multiplication is performed first. It may be beneficial to use grouping to show which operations are performed first. Grouping is simply starting an expression with '(' and ending with ')'. Therefore, the expression 3+5\*6 is equivalent to 3+(5\*6). Grouping is very important if you want to override the default behavior and have one piece of the expression evaluated first. Therefore, to make sure the + is evaluated first, the expression is written as (3+5)\*6, for a result of 48.

Operators
Operator Precedence & Grouping


Operators Overview (Part 1)

# Operators Overview

SIMPL+ operators perform functions between two or more variables. SIMPL+ operators consist of Arithmetic, Bitwise, Rational and String Operators.

Refer to [Arithmetic Operators], [Bitwise Operators], [Relational Operators], [String Operators].

Arithmetic Operators

|  |  |  |  |
|----|----|----|----|
| OPERATOR | NAME | EXAMPLE | EXPLANATION |
| \- | Negation | -X | Negate the value of X (2's Complement of X). |
| \* | Multiplication | X \*Y | Multiply X by Y (signed arithmetic). |
| / | Unsigned Division | X / Y | Divide X by Y, truncates result (unsigned arithmetic). |
| S/ | Signed Division | X S/ Y | Divide X by Y, truncates result (signed arithmetic). |
| MOD | Signed Modulo | X MOD Y | Remainder after dividing X by Y (signed arithmetic). |
| UMOD | Unsigned Modulo | X UMOD Y | Remainder after dividing X by Y (unsigned arithmetic). Only 2-Series Systems. |
| % | Signed Modulo Alias | X % Y | Translates to Signed Modulo |
| \+ | Addition | X + Y | Add the value of Y to X. |
| \- | Subtraction | X - Y | Subtract the value of Y from X. |

Bitwise Operators

|  |  |  |  |
|----|----|----|----|
| OPERATOR | NAME | EXAMPLE | EXPLANATION |
| \<\< | Shift Left | X \<\< Y | Shift X to the left by Y bits; 0 is Shifted in. |
| \>\> | Shift Right | X \>\> Y | Shift X to the right by Y bits; 0 is Shifted in. |
| {{ | Rotate Left | X {{ Y | Rotate X to the left by Y bits; full 16 bits used. Same as RotateLeft(). |
| }} | Rotate Right | X }} Y | Rotate X to the right by Y bits; full 16 bits used. Same as RotateRight(). |
| NOT | 1's Complement | NOT(X) | Change 0 bits to 1, 1 bits to 0. |
| & | Bitwise AND | X & Y | AND the bits of X with the bits of Y. |
| | | Bitwise OR | X | Y | OR the bits of X with the bits of Y. |
| ^ | Bitwise XOR | X ^ Y | XOR the bits of X with the bits of Y. |

NOTE:  For the Shift and Rotate operators, only the lower 5-bits of Y are used, giving values of Y ranging from 0 to 31. For example, if Y=600, the lower 5-bits equate to 24. Rotating a 16-bit number through 16 positions gives the original number back. Therefore, for rotating 24, the result is equivalent to rotating through 8. Shifting greater than 16 will always give a 0 as a result.

Relational Operators

NOT Operators Overview Part RotateLeft RotateRight


Operators Overview (Part 2)

|  |  |  |  |
|----|----|----|----|
| OPERATOR | NAME | EXAMPLE | EXPLANATION |
| = | Comparison | X = Y | True if X is equal to Y, False otherwise. |
| = | Assignment | X = Y | Assigns the contents in Y to X. The assignment operator cannot be used within expressions. |
| ! | Complement | ! X | If X = 0, X changes to 1. If X is different from 0, evaluates to 0. |
| \<\> | Not Equal To | X \<\> Y | X is not equal to Y. |
| \< | Unsigned Less Than | X \< Y | X is less than Y (unsigned). |
| \> | Unsigned Greater | X \> Y | X is greater than Y (unsigned). |
| \<= | Unsigned Less Than or Equal | X \<= Y | X is less or equal to Y (unsigned). |
| \>= | Unsigned Greater Than or Equal | X \>= Y | X is greater or equal to Y (unsigned). |
| S\< | Signed Less Than | X S\< Y | X is less than Y (signed). |
| S\> | Signed Greater Than | X S\> Y | X is greater than Y (signed). |
| S\<= | Signed Less Than or Equal | X S\<= Y | X is less or equal to Y (signed). |
| S\>= | Signed Greater Than or Equal | X S\>= Y | X is greater or equal to Y (signed). |
| && | Logical AND | X && Y | True if X and Y are both non-zero. False otherwise. |
| || | Logical OR | X || Y | True if either X or Y is non-zero. False otherwise. |

 All of the above operators, with the exception of the negation (-), NOT, and complement (!) operators, are called binary operators. Binary operators take two values, perform an operation, and return a third value as a result. For example, 5 + 6 would return the value of 11. The arguments for a given operator are called its operands. In the above example, the + sign is the operator and 5 and 6 are the operands.

The negation, NOT, and complement operators are called unary operators, which means it takes a single number and performs an operation. In this case, the negation operator performs a negate, or 2's complement. A 2's complement takes a 16-bit number, bitwise inverts it, and adds 1. The operand in a negation is the value being negated. Operands do not have to be simple numbers. They may also be variables or the results of a function call. For example, in the expression -X, the - sign is the operator and the variable X is the operand.

Note that the '=' is used as both comparison and assignment. The behavior depends on the type of statements that are being written.

String Operators

Shifting greater than 16 will always give a 0 as a result. Relational Operators


Operators Overview (Part 3)

| OPERATOR | NAME         | EXAMPLE  | EXPLANATION                                                                                |
| -------- | ------------ | -------- | ---------------------------------------------------------------------------------------------------------------- |
| =        | Assignment   | A$ = B$  | Assigns the contents in B$ to A$. NOTE: Not allowed in expressions because it would be confused with Comparison. |
| =        | Comparison   | A$ = B$  | A$ equal B$                                                                                |
| <>       | Not Equal To | A$ <> B$ | A$ is not equal to B$                                                                                |
| <        | Less Than    | A$ < B$  | A$ is less than B$                                                                                |
| >        | Greater Than | A$ > B$  | A$ is greater than B$                                                                                |

For less than and greater than operations, the string is evaluated in ASCII order. For example, the comparison "ABC" \> "ABD" would be false. The system looks character by character; the first two characters are identical in both strings, and when it evaluated the characters C (ASCII 67) vs. D (ASCII 68), the result is false.

  [Arithmetic Operators]: Arithmetic_Operators.md
  [Bitwise Operators]: Bitwise_Operators.md
  [Relational Operators]: Relational_Operators.md
  [String Operators]: ../Language_Constructs_&_Functions/String_Formatting_&_Printing_Functions/String_Operators.md

Arithmetic Bitwise Operators Overview Part Relational String

Arithmetic Operators
Bitwise Operators
Relational Operators
String Operators

The behavior depends on the type of statements that are being written. String Operators


Relational Operators

# Relational Operators

Relational Operators

|  |  |  |  |
|----|----|----|----|
| OPERATOR | NAME | EXAMPLE | EXPLANATION |
| = | Comparison | X = Y | True if X is equal to Y, False otherwise. |
| = | Assignment | X = Y | Assigns the contents in Y to X. The assignment operator cannot be used within expressions. |
| ! | Complement | ! X | If X = 0, X changes to 1. If X is different from 0, evaluates to 0. |
| \<\> | Not Equal To | X \<\> Y | X is not equal to Y. |
| \< | Unsigned Less Than | X \< Y | X is less than Y (unsigned). |
| \> | Unsigned Greater | X \> Y | X is greater than Y (unsigned). |
| \<= | Unsigned Less Than or Equal | X \<= Y | X is less or equal to Y (unsigned). |
| \>= | Unsigned Greater Than or Equal | X \>= Y | X is greater or equal to Y (unsigned). |
| S\< | Signed Less Than | X S\< Y | X is less than Y (signed). |
| S\> | Signed Greater Than | X S\> Y | X is greater than Y (signed). |
| S\<= | Signed Less Than or Equal | X S\<= Y | X is less or equal to Y (signed). |
| S\>= | Signed Greater Than or Equal | X S\>= Y | X is greater or equal to Y (signed). |
| && | Logical AND | X && Y | True if X and Y are both non-zero. False otherwise. |
| || | Logical OR | X || Y | True if either X or Y is non-zero. False otherwise. |

 All of the above operators, with the exception of the negation (-), NOT, and complement (!) operators, are called binary operators. Binary operators take two values, perform an operation, and return a third value as a result. For example, 5 + 6 would return the value of 11. The arguments for a given operator are called its operands. In the above example, the + sign is the operator and 5 and 6 are the operands.

The negation, NOT, and complement operators are called unary operators, which means it takes a single number and performs an operation. In this case, the negation operator performs a negate, or 2's complement. A 2's complement takes a 16-bit number, bitwise inverts it, and adds 1. The operand in a negation is the value being negated. Operands do not have to be simple numbers. They may also be variables or the results of a function call. For example, in the expression -X, the - sign is the operator and the variable X is the operand.

Note that the '=' is used as both comparison and assignment. The behavior depends on the type of statements that are being written.


Signed vs Unsigned Arithmetic

# Signed vs Unsigned Arithmetic

ANALOG_INPUT, ANALOG_OUTPUTs, and INTEGER in SIMPL+ are 16-bit quantities. A 16-bit quantity can range from 0 - 65535 when it is treated without having a sign (positive or negative). If a 16-bit number is treated as signed in SIMPL+, the range becomes -32768 to 32767. The range from -32768 to -1 maps into 32768 to 65535. Expressed mathematically, the mapping is 65536 - AbsoluteValue(Number). The values are treated differently depending on whether signed or unsigned comparisons are used. Another way is as follows.

|          |             |           |       |
|----------|-------------|-----------|-------|
| Signed   | 0  -  32767 | 32768  -  | 65535 |
| Unsigned | 0  -  32767 | -32768  - | -1    |

Assignments may be directly done with negative constants, for example:

    INTEGER I, J;

    I = -1;

    J = 65535;

Results in I being equivalent to J.

Example:

    IF (65535 S\> 0)

        X=0;

    ELSE

        X=1;

Above, the value of X is set to 1 since in signed arithmetic, 65535 is the same as -1, which is not greater than 0.

    IF (65535 \> 0)

        X=0;

    ELSE

        X=1;

Above, the value of X is set to 0 since in unsigned arithmetic, 65535 is greater than 0.

ANALOG_INPUT AbsoluteValue Arithmetic ELSE IF INTEGER Signed Unsigned


Bookmarks

# Bookmarks

From the Bookmarks selection on the Edit menu, you can choose Toggle Bookmark, Previous Bookmark, Next Bookmark or Clear Bookmarks. These choices can also be made by clicking on the icons in the SIMPL+ toolbar (shown below),

or by using the hot keys; Ctrl F2 to toggle a bookmark (add or remove) and F2 to jump to the Next Bookmark.

Programming Environment
BookMarks
Bookmarks


Compile Output Files

# Compile Output Files

Compiling SIMPL+ modules will result in several output files being written into the project folder.  These files will appear both in the module's project folder and into a temporary folder called SPlsWork.  The files written are as follows:

The SIMPL+ Module's project directory will contain the following files:

\<module\>.usp  -  SIMPL+ User Module (Never Deleted)

\<module\>.usl  -  SIMPL+ User Library (Never Deleted)

\<module\>.ush  -  SIMPL+ User Module Header File (Never Deleted - File is written upon SIMPL+ Module compilation)

SPlusWork Directory will contain the following files:

\<module\>.inf  -  SIMPL+ Module Information File  (Remains after a successful compilation)

\<module\>.spl  -  SIMPL+ intermediary file  (Remains after a successful compilation)

\<module\>.h  -  SIMPL+ intermediary file  (Remains after a successful compilation)

\<module\>.o  -  SIMPL+ intermediary file  (Remains after a successful compilation)

\<module\>.c  -  SIMPL+ intermediary file  (Deleted after SIMPL+ Module compilation)

SIMPL+ Modules are only compiled if the module has not been changed since the last successful compilation.  The compiler is optimized not to recompile a module during the build process once it is has been compiled successfully.  SIMPL+ Libraries and modules contained within User Macros are not optimized in this manner and they will always be recompiled for each build process.  Selecting "Build All" from the SIMPL+ Build Menu will force the module and all included libraries to be recompiled.

Programming Environment
Compile Output Files

Compile File Files Library Module Output


Compiler Options

# Compiler Options

Execute SIMPL+ Cross Compiler - After target files are compiled, the cross compiler can be launched from the SIMPL+ environment. This will enable you to generate the target file that will be uploaded to the operating system. Normally, the SIMPL environment will handle this, since it is responsible for uploading the target file to the operating system.

Display Compile Warnings - When selected, the compiler displays all program warnings during compile in the compile output window. The total number of warnings will always be displayed whether this option is selected or not.

Programming Environment
Compiler Options


Cursor Positioning

# Cursor Positioning

Cursor Positioning, Auto-Indent - When the 'enter' key is pressed, the cursor will automatically indent to the same initial tab position as in the current line.

- To manually indent a block of text, highlight the block and press TAB.

- To manually outdent a block of text, highlight the block and press SHIFT and TAB.

- If you have manually inserted spaces for tabs, then pressing SHIFT TAB will only outdent by only one space.

Cursor Positioning, Allow cursor positioning past end of line - If checked, the cursor will be allowed to be placed anywhere within the text editor. This includes any white-space area. Disabling this option will force the cursor to the end of the current line selected when the cursor is clicked on any white-space past the end of the line.

Programming Environment
Cursor Positioning


Edit Menu

# Edit Menu

The Edit Menu contains the typical Windows commands and hot keys as well as some commands that are peculiar to SIMPL+.

Interactive: click on an Edit Menu command to learn more about it. If you place your cursor on a hot spot, a screen tip will display.

NOTE: Only Select All, Find Next, Bookmarks, Insert Category and Preferences are enabled at this time.

Programming Environment
EditMenu
Edit Menu


Edit Select All

# Edit Select All

This commend, whether initiated by the menu choice or the hot keys Ctrl+A, selects everything in the current SIMPL+ module.

Programming Environment
EditSelectAll
Edit Select All


Edit Preferences

# Edit Preferences

The Edit Preferences Dialog, contains a pair of tabs, one being the Text Editor tab and the other being Target Devices.

The Text Editor Tab now incorporates color controls for the SIMPL+ Programming Environment. This feature allows you to set the colors for the background, comments, functions, keywords, strings, Symbol Help Text, and plain text. You can tell with a glance, based on the color you specify, what you're working on.

Interactive: click on an area of the dialog for more information. If you place your cursor on a hot spot, a screen tip will display.

The Text Editor Tab

Target Devices Tab

Programming Environment
Edit Preferences


Edit Preferences Text Editor Colors

# Edit Preferences Text Editor Colors

This allows you to customize SIMPL+ Editor. You can select the color of the background, comments, functions, keywords, strings, symbol help text and text.

Programming Environment
Edit Preferences Text Editor Colors


Find Next

# Find Next

This is the usual extension of the Find command, Ctrl+F3. It is initiated by the menu command, Find Next or the hot key F3.

Programming Environment
FindNext
Find Next


Insert Category

# Insert Category

Displays a list of all available categories for the symbol tree in the SIMPL environment. This list is for reference only.

Symbol Tree Category List in SIMPL

To specify a category for a SIMPL+ module, the #CATEGORY directive must be used with a category specified in this list. If a category name is typed in that does not exist in the Symbol Tree Category list, the SIMPL+ module will default to the category type, Miscellaneous.

Insert #CATEGORY Toolbar Pull-Down Menu in SIMPL+

Symbol Tree Category Pop-Up Window

NOTE: The Enter Custom Category Name field only appears when category 46 is selected.

Category Selection Insertion Alert


Programming Environment Overview

# Programming Environment Overview

While running SIMPL, select File | New SIMPL+ and the SIMPL+ programming environment opens the SIMPL+ Editor.

By default, the SIMPL+ Editor opens the Module Information template which is divided into sections consisting of the [Compiler Directives], [Libraries], Inputs and Outputs, [Structure Definitions], Global Variables and [Functions], etc., required to build a SIMPL+ program.  Each of these sections contains commented code (in green) that makes it easy to remember the language syntax and structure. Simply locate the necessary lines in the desired section, uncomment them (the code color changes to blue), and add the appropriate code. To uncomment a line of code, either remove the "//" that appears at the start of the line or remove the multi-line comment indicators /\*…\*/.

NOTE: When you declare a [User-Defined Function], it will display in Gray. If you right-click on the gray text, a pop-up menu will display allowing you to select Go To . . . to jump to the place in the program where your function is used. Copy, Paste and Cut are available on the pop-up menu as well.

The following screen capture shows the SIMPL+ programming environment as it opens when you select New SIMPL+ Module from the File Menu.

Interactive: click on the menus and tool bar icons for more information about them. If you place your cursor on a hot spot, a screen tip will display.

NOTE: At this time, only the Edit Menu is active.

  [Compiler Directives]: ../Language_Constructs_&_Functions/Compiler_Directives/Overview.md
  [Libraries]: ../Language_Constructs_&_Functions/User_Defined_Functions/Function_Libraries.md
  [Structure Definitions]: ../Language_Constructs_&_Functions/Declarations/STRUCTURES.md
  [Functions]: ../Language_Constructs_&_Functions/Functions_Overview.md
  [User-Defined Function]: ../Language_Constructs_&_Functions/User_Defined_Functions/User_Defined_Functions_Overview.md

Programming Environment
Overview
Programming Environment Overview

Compiler Defined Definitions Directives Environment Function Functions Libraries Overview Programming Structure User

Compiler Directives
Libraries
Structure Definitions
Functions
User-Defined Function


Tabs

# Tabs

Tab Size - The number of spaces that equal 1 tab character.

Insert Spaces for tabs - Spaces will be inserted in place of the tab character.


Target Selection

# Target Selection

When compiling a SIMPL+ module at least one target control system type needs to be selected for the SIMPL+ module to compile successfully. Starting with SIMPL v. 4.14.xx the default target selections for a new SIMPL+ module are 3-Series AND 4-series control systems.. Note that on open, existing SIMPL+ modules will also target 4-Series control system class by default..

For example, if a SIMPL+ module was previously targeting 2-Series only, it will target 2-Series and 4-Series when opened in SIMPL v. 4.14.xx and later.

Selecting a target implies that the module MUSTwork for that target and any statements that are not valid for that target are NOT permitted. It does NOT mean that the module won't work for other targets. For example, most SIMPL+ modules targeting 4-Series control systems can be uploaded and expected to work on 3-Series control systems as well.

NOTE: A SIMPL+ module can be added to the SIMPL program only if that module targets the control system present in the SIMPL program;\
\
If the SIMPL+ module does NOT target the control system present in the SIMPL program, the SIMPL+ module cannot be added to SIMPL program.\

Changes to the targeted control system types can be made via the SIMPL+ toolbar or from the **Build** menu.

Target Selection from the toolbar

When one or more target options are selected (buttons appear "pressed"), the control system type target is included during compilation; when an option is NOT selected, the control system target type is NOT included during compilation.

In the example below only the 4-Series control systems target is selected, thus only the 4-Series control system target will be included when compiling:

Additionally, target selection can be specified from the **Build** menu:

Target Selection from the Build Menu

When one or more target options are selected (checkmark is displayed), the control system type target is included during compilation; when an option is NOT selected, the control system target type is NOT included during compilation.

NOTE: In older versions of SIMPL+, the settings for the target types were system-wide. Those settings applied to all SIMPL+ modules that were opened and were not specific to the active module being edited.\
\
In SIMPL+ version 3.00 and later, the target type setting is specific only to the active module being edited and saved within that module. The toolbar buttons reflect the target type of the active module within the SIMPL+ environment.

NOTE: If a program is compiled for the wrong type of control system, an error message may appear when attempting to upload, and the program must be re-compiled.

.

**See also:**

[IF_SERIES2]

[IF_SERIES3]

[IF_SERIES4]

  [IF_SERIES2]: ../Language_Constructs_&_Functions/Encoding/_IF_SERIES2.md
  [IF_SERIES3]: ../Language_Constructs_&_Functions/Encoding/_IF_SERIES3.md
  [IF_SERIES4]: ../Language_Constructs_&_Functions/Encoding/_IF_SERIES4.md

Programming Environment
Target Selection
Target Selection


Windows Color Picker Dialog

# Windows Color Picker Dialog

Clicking on this button opens the standard Windows Color Picker Dialog, allowing you to choose the color of a variety of SIMPL+ Editor attributes.

Programming Environment
Windows Color Manager
Windows Color Picker Dialog


Windows Font Picker Dialog

# Windows Font Picker Dialog

Use this to select the font you'd like displayed for a selected SIMPL+ Editor attribute. Microsoft apparently refers to this as a picker instead of a "Selection Dialog". Oh, well.

Programming Environment
Windows Font Picker Dialog


SIMPL+ Revisions

# SIMPL+ Revisions

Download the latest revisions from [www.crestron.com/updates]. TBD

  [www.crestron.com/updates]: http://www.crestron.com/updates


Software Requirements

# Software Requirements

SIMPL+ has several versions. Earlier versions of SIMPL+ do not contain features and constructs found in later revisions. Each version of SIMPL+ requires a minimum revisions of SIMPL and Control System Update (UPZ or, for 2-Series control systems, CUZ) files. The specifications are listed below.

Software Requirements

|  |  |  |  |
|----|----|----|----|
| SIMPL+ VERSION | MINIMUM SIMPL REQUIRED | MINIMUM UPZ | MINIMUM CUZ |
| Version 1.00 | 1.30.01 | 5.04.11 | N/A |
| Version 2.00 | 1.40.02 | 5.10.00 | N/A |
| Version 3.00 | 2.00 | N/A | 1.00 |


Compact Flash Functions

# Compact Flash Functions

The 2‑series and newer control systems support reading and wiritng to and from compact flash cards and other storage mediums.

Data storage is a valuable, powerful and important part of programming. The ability to store and retrieve data from a removable data source can provide many useful and powerful solutions. Some of these solutions include the ability to backup data, transferring data from one control system to another, reading and writing data to and from formats that other database programs can recognize, and implementing database‑driven programs (the ability for a program to act dynamically based on actions defined in the database).

The SIMPL+ file functions perform file access with the control system’s compact flash card. Because of the overhead involved with maintaining current directory and file positions, there are restrictions on file I/O. Each SIMPL+ thread (main loop or event handler) that requires file operations must first identify itself with the operating system. This is done with the function, `StartFileOperations`. Before terminating the thread, the function, `EndFileOperations` must be called. Files cannot be opened across threads. In other words, you cannot open a file in one thread, such as `Function Main`, and then access the file with the returned file handle in another thread, such as an event handler. Files should be opened, accessed and closed within the same thread.

SIMPL Plus Tutorial
Compact Flash Functions
TP Compact-Flash-Functions

Compact Flash Functions > CheckForDisk and WaitForNewDisk


CheckForDisk and WaitForNewDisk

## CheckForDisk and WaitForNewDisk

Before accessing compact flash, the program must either first check to see if a compact flash card exists within the control system, or wait for a card to be inserted.

Certain programs might rely on the compact flash card being inserted within the control system. The function in the example below, `CheckForDisk`, will test for the existence of a compact flash card within the control system. The function will return an error code and the program can act accordingly.

Other programs might prompt the end‑user to insert a compact flash card. The function in the example below, `WaitForNewDisk`, will halt the program and resume when a compact flash card is detected within the control system.

The following is an example of a program that needs to read data from a compact flash card upon startup:

FUNCTION ReadMyCompactFlashCard()\
{\
// call functions to read the compact flash card\
//\
// Note that this function will exist within the same\
// thread as the calling function (Function Main).\
// Because of this, the functions, StartFileOperations\
// and EndFileOperations should not be used here.}

Function Main()\
{\
StartFileOperations();

if (CheckForDisk() = 1)\
    Call ReadMyCompactFlashCard();\
else if ( WaitForNewDisk() = 0 )\
    Call ReadMyCompactFlashCard();

EndFileOperations(); }

If the program is dependent upon data that read in from the compact flash card, it is imperative for the program to validate the existence of the card. Otherwise, the program will not have the necessary data needed to execute properly. The above function will first check if the compact flash card is already inserted into the control system upon system startup. If so, it will call the user‑defined function, `ReadMyCompactFlashCard`, to perform any file read operations on the compact flash card. If the compact flash card was not found in the control system, the program will wait for the card to be inserted before continuing. Once inserted, the same function, `ReadMyCompactFlashCard`, is called.

SIMPL Plus Tutorial
Compact Flash Functions
TP Compact-Flash-Functions
CheckForDisk and WaitForNewDisk

CheckForDisk EndFileOperations FUNCTION Main ReadMyCompactFlashCard StartFileOperations WaitForNewDisk and

Compact Flash Functions > CheckForDisk and WaitForNewDisk > Reading and Writing Data

In other words, you cannot open a file in one thread, such as `Function Main`, and then access the file with the returned file handle in another thread, such as an event handler. Files should be opened, accessed and closed within the same thread.


Reading and Writing Data

### Reading and Writing Data

Once the existence of the compact flash card is verified, the reading and writing of data can be performed. Data can be read or written either with individual elements (i.e., a single integer or string), or with entire structures of data.

Because each datatype (i.e.: `INTEGER`, `STRING`, `LONG_INTEGER`) uses a different amount of storage in memory, there are different functions to read and write each of these types. The return value of each of these functions is the actual number of bytes read or written to the file. The reason why different functions have to be called instead of having just one function is for the following reason. Data elements are written to a file by inserting one element after another. The file does not contain any information as to what that data is or how it is to be extracted out. It is up to the program that will ultimately read that file to know exactly what is contained within the file and how to extract the data back out of it.

The following example demonstrates this:

DIGITAL_INPUT readCompactFlashCard;\
DIGITAL_INPUT writeCompactFlashCard;

INTEGER myInt;\
LONG_INTEGER myLongInt;\
STRING myStr[50];

PUSH writeCompactFlashCard\
{\
SIGNED_INTEGER nFileHandle;\
INTEGER nNumBytes;

StartFileOperations();

nFileHandle = FileOpen( "\\CF0\\MyFile", _O_WRONLY | _O_CREAT | _O_BINARY );\
if( nFileHandle \>= 0 )\
{nNumBytes = WriteInteger( nFileHandle, myInt );\
nNumBytes = WriteLongInteger( nFileHandle, myLongInt );\
nNumBytes = WriteString( nFileHandle, myStr );

FileClose( nFileHandle );}

EndFileOperations();}

PUSH readCompactFlashCard\
{\
SIGNED_INTEGER nFileHandle;\
INTEGER nNumBytes;

StartFileOperations();

nFileHandle = FileOpen( "\\CF0\\MyFile", _O_RDONLY | _O_BINARY );\
if( nFileHandle \>= 0 )\
{nNumBytes = ReadInteger( nFileHandle, myInt );\
nNumBytes = ReadLongInteger( nFileHandle, myLongInt );\
nNumBytes = ReadString( nFileHandle, myStr );

FileClose( nFileHandle );}

EndFileOperations();}

The functions, `ReadStructure` and `WriteStructure`, automate the reading and writing of the individual fields within the structure. These functions do not return the number of bytes read or written. Instead, both functions have an additional argument that will contain the number of bytes read or written after the function call executes.

The following example demonstrates this:

DIGITAL_INPUT readCompactFlashCard;\
DIGITAL_INPUT writeCompactFlashCard;

STRUCTURE myStruct\
{\
INTEGER myInt;\
LONG_INTEGER myLongInt;\
STRING myStr[50];\
}\
myStruct struct;

PUSH writeCompactFlashCard\
{SIGNED_INTEGER nFileHandle;\
INTEGER nNumBytes;

StartFileOperations();

nFileHandle = FileOpen( "\\CF0\\MyFile", _O_WRONLY | _O_CREAT | _O_BINARY );if( nFileHandle \>= 0 )\
{"WriteStructure( nFileHandle, struct, nNumBytes );

Print( “The number of bytes written = %d”, nNumBytes );

FileClose( nFileHandle );}

EndFileOperations();}

PUSH readCompactFlashCard\
{SIGNED_INTEGER nFileHandle;\
INTEGER nNumBytes;

StartFileOperations();

nFileHandle = FileOpen( "\\CF0\\MyFile", _O_RDONLY | _O_BINARY );\
if( nFileHandle \>= 0 )\
{ReadStructure( nFileHandle, myInt, nNumBytes );

Print( “The number of bytes read = %d”, nNumBytes );

FileClose( nFileHandle );}

EndFileOperations();}

SIMPL Plus Tutorial
Compact Flash Functions
TP Compact-Flash-Functions
Reading and Writing Data

DIGITAL_INPUT Data EndFileOperations FileClose FileOpen INTEGER LONG_INTEGER PUSH Print ReadInteger ReadLongInteger ReadString ReadStructure Reading SIGNED_INTEGER STRING STRUCTURE StartFileOperations WriteInteger WriteLongInteger

If the compact flash card was not found in the control system, the program will wait for the card to be inserted before continuing. Once inserted, the same function, `ReadMyCompactFlashCard`, is called.


Controlling Program Flow: Branching

# Controlling Program Flow: Branching

In any substantial program, making decisions must control the program. SIMPL+ provides two constructs for branching the program based on the value of expressions: `if‑else` and the `switch‑case` statement.

SIMPL Plus Tutorial
Controlling Program Flow Branching
TP Controlling-Program-Flow-Branching
Controlling Program Flow: Branching

Controlling Program Flow: Branching > if‑else


if‑else (Part 1)

## if‑else

`if‑else` is the most commonly used branching construct. In its most basic form, it is structured as follows.

if (expression1)\
{\
// do something here}

Where `expression1` represents any valid SIMPL+ expression, including variables, function calls, and operators. If this expression evaluates to `True`, then the code inside the braces is executed. If this expression evaluates to `False`, the code inside the braces is skipped.

What is the definition of `True` and `False` in SIMPL+? As was discussed in [Working with Data (Variables)], expressions, which evaluate to a non‑zero result, are considered `True`, and expressions that evaluate to `0` are considered `False`. For example, refer to the expressions in the table that follows.

| Expression | Evaluates to                           |
|------------|----------------------------------------|
| a = 3      | true if a=3, false otherwise           |
| b\*4 ‑ a/3 | true as long as the result is non-zero |
| 1          | always true                            |
| 0          | always false                           |

Expressions {cellspacing="0"}

One limitation with the `if` construct, as shown above, is that the code inside the `if` is run whenever `expression1` evaluates as `True`, but any code after the closing braces runs regardless. It is often useful to execute one set of code when a condition is `True` and then another set of code if that same condition is `False`. For this application, use the `if‑else` construct, which looks like the following.

if (expression1)\
{\
// do something if expression1 is true}\
else\
{\
// do something else if expression1 is false}

NOTE: Programming to anticipate user errors and handle them appropriately is called error‑trapping. It is a recommended programming practice.

It should be clear that the code following the `if` runs whenever `expression1` evaluates to `True` and the code following the `else` executes whenever `expression1` evaluates to `False`. Obviously, there can never be a case where both sections of code execute together.

The following example is designed to control a CD changer. Before telling the CD player to go to a particular disc number, it checks to see that the analog value, which represents the disc number, does not exceed the maximum value.

#DEFINE_CONSTANT NUMDISCS 100

ANALOG_INPUT disc_number;\
STRING_OUTPUT CD_command, message;

CHANGE disc_number\
{\
if (disc_number \<= NUMDISCS)\
{CD_command = "DISC " + itoa(disc_number) + "\r";\
message = "Changing to disc " + itoa(disc_number) + "\n";}\
else\
{message = "Illegal disc number\n";}}

There is one last variation on the `if‑else` statement. In the example above, the decision to be made is binary. That is, do one thing if this is true, otherwise do something else. In some cases decisions are not that straight forward. For example, to check the current day of the week, execute one set of code if it is Saturday, another set of code if it is Sunday, and yet some other code if it is any other day of the week. One way to accomplish this is by using a series of `if‑else` statements. For this example, the code might look like the following.

today = GetDayOfWeekNum();          // gets the current day of the week

SIMPL Plus Tutorial
Controlling Program Flow Branching
TP Controlling-Program-Flow-Branching
if‑else


if‑else (Part 2)

if (today = 0)                      // is today Sunday?\
{\
// code to run on Sundays}\
else if (today = 5)                 // is today Friday?\
{\
// code to run on Friday}\
else if (today = 6)                 // is today Saturday?\
{\
// code to run on Saturdays} else                              // only gets here if the first three\
{                                   // conditions are false\
// code to run on all other days}

NOTE: There can be as many if‑else statements in a single construct as necessary. However, sometimes tasks like these are better handled with the switch‑ case construct, discussed in the next section.

Finally, note that `if` statements can be nested inside other if statements.

For this example, the code might look like the following. today = GetDayOfWeekNum();          // gets the current day of the week


switch-case

## switch-case

In the last section, it was shown that the `if‑else` construct can be used for making complex decisions. Also it was used for making a choice between mutually exclusive conditions (conditions that cannot coexist), the syntax can become cumbersome. For this particular case SIMPL+ offers the switch‑case construct.

Think of `switch‑case` as a compact way of writing an `if‑else` construct. The basic form of the `switch‑case` is shown after this paragraph.

switch (expression)\
{\
case (expression1):\
{\
// code here executes if\
// expression = expression1}\
case (expression2):\
{\
// code here executes if\
// expression = expression2}\
default:\
{\
// code here executes if none\
// of the above cases are true}}

NOTE: The use of the default keyword allows specific code to execute if none of the other cases are true. This is identical to the final else statement in the `if‑else` construct mentioned in [Controlling Program Flow: Branching].

Examine an example using the `switch‑case` construct. Perhaps there is a variable that should hold the number of days in the current month. The following example uses `switch‑case` to set the value of this variable.

switch (getMonthNum())\
{\
case (2): //February\
{if (leapYear) // this variable was set elsewhere\
numdays = 29;else\
numdays = 28;}\
case (4): // April\
   numdays = 30;\
case (6): // June\
   numdays = 30;\
case (9): // September\
   numdays = 30;\
case (11): // November\
   numdays = 30;\
default:   // Any other month\
   numdays = 31;\
}

Notice that curly braces did not enclose many of the statements in the previous example. For most SIMPL+ constructs, the braces are only needed when more than one statement is to be grouped together. If the program has only a single statement following the case keyword, then the braces are optional.

  [Working with Data (Variables)]: ../Working_With_Data/TP_Working-with-Data-(Variables).md
  [Controlling Program Flow: Branching]: #if-else

SIMPL Plus Tutorial
Controlling Program Flow Branching
TP Controlling-Program-Flow-Branching
switch-case

Controlling Program Flow: Branching > switch-case

However, sometimes tasks like these are better handled with the switch‑ case construct, discussed in the next section. Finally, note that `if` statements can be nested inside other if statements.


Controlling Program Flow: Loops

# Controlling Program Flow: Loops

[Controlling Program Flow: Branching] discussed constructs for controlling the flow of a program by making decisions and branching. Sometimes a program should execute the same code a number of times. This is called looping. SIMPL+ provides three looping constructs: the `for` loop, the `while` loop, and the `do‑until` loop.

SIMPL Plus Tutorial
Controlling Program Flow Loops
TP Controlling-Program-Flow-Loops
Controlling Program Flow: Loops

Controlling Program Flow: Loops > for Loops


for Loops (Part 1)

## for Loops

The `for` loop is useful to cause a section of code to execute a specific number of times. For example, consider clearing each element of a 15‑element string array (set it to an empty string). Use a for loop set to run 15 times and clear one element each time through the loop.

Control the number of loops a `for` loop executes through the use of an index variable, which must be an integer variable previously declared in the variable declaration section of the program. Specify the starting and ending values for the index variable, and an optional step value (how much the variable increments by each time through the loop). Inside the loop, the executing code can reference this index.

The syntax of the `for` loop is as follows.

for (\<variable\> = \<start\> to \<end\> step \<stepValue\>)\
{\
// code in here executes each time through the loop}

To see an example of the `for` loop use the situation alluded to above. That is, a need to clear each string element in a string array. A program to accomplish this might look like the following.

DIGITAL_INPUT clearArray;             // a trigger signal\
INTEGER i;                            // the index variable\
STRING stringArray[50][14];           // a 15-element array\

PUSH clearArray                       // event function\
{\
for (i = 0 to 14)\
{stringArray[i] = "";             // set the ith element\
                                 // to an empty string\
print("cleared element %d\n",i); // debug message}                                   // this ends the for\
                                    // loop}                                      // this ends the push\
                                       // function

In this example, the loop index `i` is set to run from `0 to 14`, which represents the first and last elements in `stringArray` respectively. Also notice that the step keyword is omitted. This keyword is optional and if it is not used, the loop index increments by 1 each time through the loop. To clear only the even‑numbered array elements, the following could have used.

for (i = 0 to 14 step 2)\
{ . . . }

The step value can also be negative, allowing the loop index to be reduced by some value each time though the loop.

The `for` loop flexibility can be enhanced further by using expressions instead of constant values for the start, end, and step values. For example, there might be a need to add up the value of each byte in a string in order to calculate the value of a `checksum` character. Since the length of the string can change as the program runs, the number of iterations through the loop is unknown. The following code uses the built‑in function, `len`, to determine the length of the string and only run through the for loop the necessary number of times. System functions are described in detail in [Using System Functions].

checksum = 0; // initialize the chucksum variable

/\* iterate through the string and add up the bytes.\
Note that the { } braces are not needed here\
because the contents of the for-loop is only\
a single line of code \*/for (i = 1 to len(someString))\
checksum = checksum + byte(someString,i);

SIMPL Plus Tutorial
Controlling Program Flow Loops
TP Controlling-Program-Flow-Loops
for Loops

DIGITAL_INPUT INTEGER Loops PUSH Part STRING for

This is called looping. SIMPL+ provides three looping constructs: the `for` loop, the `while` loop, and the `do‑until` loop.


for Loops (Part 2)

/\* now add the checksum byte on to the string\
using the chr function. Note that in this\
example we only use the low-order byte from\
the checksum variable \*/someString = someString + chr(checksum);

System functions are described in detail in [Using System Functions]. checksum = 0; // initialize the chucksum variable

/\* iterate through the string and add up the bytes.\
Note that the { } braces are not needed here\
because the contents of the for-loop is only\
a single line of code \*/for (i = 1 to len(someString))\
checksum = checksum + byte(someString,i);


while and do‑until Loops (Part 1)

## while and do‑until Loops

The `for` loop discussed in an earlier section is useful for iterating through code a specific number of times. However, sometimes the exact number of times a loop should repeat is unknown. Instead, it may be necessary to check to see if a condition is true after each loop to decide whether or not the loop should execute again.

There are two looping constructs in SIMPL+ which allows execution of a loop only for as long as a certain condition is true. These are the `while` and `do‑until` loops. The `while` loop has the following syntax.

while (expression)\
{\
\<statements\>}

When the `while` statement is executed, the expression contained in parentheses is evaluated. If this expression evaluates to True, then the statements inside the braces are executed. When the closed brace is reached, the program returns to the `while` statement and reevaluates the expression. At this point the process is repeated. It should become clear that the code inside the braces is executed over and over again as long as the `while` expression remains True.

The nature of the `while` loop means that it is the responsibility of the programmer to ensure that the loop is exited at some point. Unlike the `for` loop discussed previously, this loop does not run for a set number of times and then finishes. Consider the example after this paragraph.

x = 5;\
while (x \< 10)\
{\
y = y + x;\
print("Help me out of this loop!\n");}

NOTE: Endless loops cause the SIMPL+ module (in which they occur) to rerun the same code forever. However, due to the multi‑tasking nature of the operating system, an endless loop in one module does not cause the rest of the SIMPL program (including other SIMPL+ modules) to stop running. This is discussed in more detail in [Understanding Processing Order].

This example shows an endless loop. That is, a loop that runs forever and never exits. The problem is that the value of the `while` expression never changes once the loop is entered. Thus the expression can never evaluate to `False`. Include code inside the loop that affects the `while` expression (in this case the variable `x` must be modified in some way) and allows the loop to exit at some point.

The `do‑until` looping construct is similar to the `while` loop. The difference lies in where the looping expression is evaluated and how this evaluation affects the loop. To see the difference, examine the form of a `do‑until` loop.

do\
{\
\<statements\>} until (expression)

From the syntax, it is obvious that the looping expression for a `do‑until` appears after the looping code. This expression appears before the code in a `while` loop. This discrepancy affects the way the loop is initially entered. As was shown above, a `while` loop first evaluates the expression to see if it is `True`. If it is, then the loop runs through one time and then the expression is evaluated again.

SIMPL Plus Tutorial
Controlling Program Flow Loops
TP Controlling-Program-Flow-Loops
while and do‑until Loops

Controlling Program Flow: Loops > while and do‑until Loops


while and do‑until Loops (Part 2)

The `do‑until` loop differs from this in that it always executes at least one time. When the `do` keyword is reached, the code that follows (enclosed in braces) is executed before the value of the `until` expression is evaluated. After the initial pass through this code, the value of this expression determines whether or not the code should be executed again. Here lies the other difference between the `while` and `do‑until`. The `while` loop executes as long as the expression remains `True`. A `do‑until` loop executes until an expression becomes `True`.

When deciding which type of loop should be used, first understand that using any of the three types of loops discussed here can solve many problems. However, one particular loop is usually better suited for a given application than the others. As a general rule of thumb, when the number of iterations the code should execute is known, a `for` loop is preferred. A `while` or a `do‑until` loop is ideal to execute a section of code continuously based on the value of some expression.

Once a `while` or a `do‑until` loop is determined suitable for a particular application, the question becomes which one of the two should be used? Once again realize that either one can usually accomplish the goal, but one type of loop may require less coding or be more readable in some cases. The basic question to ask is whether or not the loop needs to run through at least one time. If so, a `do‑until` is the best choice. If instead, the value of an expression should be checked, then use the `while` loop.

As was shown above, a `while` loop first evaluates the expression to see if it is `True`. If it is, then the loop runs through one time and then the expression is evaluated again.


Exiting from Loops Early

## Exiting from Loops Early

All three loops discussed above have built‑in ways to exit. The `for` loop exits when the index variable reaches the stated maximum. The `while` loop exits when the expression becomes `False`. The `do‑until` loop exits when the expression becomes `True`.

Sometimes programming tasks do not always fall neatly into place regarding loops and it may be desirable (or necessary) to exit a loop prematurely. Consider the following example.

INTEGER x,y;

for (x = 3 to z)\
{\
y = y + x\*3 ‑ z\*z;\
if (y = 0)break;}

Notice that in most (if not all) cases, the need for the break statement could be avoided by the use of a different type of loop. In the example above, this could be accomplished by using a `do‑until` loop. Consider the following.

x = 3;

do\
{\
y = y + x\*3 ‑ z\*z;\
x = x + 1;} until ((y = 0) || (x = z))

Either technique would be considered acceptable.

  [Controlling Program Flow: Branching]: ../Controlling_Program_Flow_Branching/TP_Controlling-Program-Flow-Branching.md
  [Using System Functions]: ../Using_System_Functions/TP_Using-System-Functions.md
  [Understanding Processing Order]: ../Understanding_Processing_Order/TP_Understanding-Processing-Order.md

SIMPL Plus Tutorial
Controlling Program Flow Loops
TP Controlling-Program-Flow-Loops
Exiting from Loops Early

Branching Controlling Early Exiting Flow Functions INTEGER Loops Order Processing Program System Understanding Using from

Controlling Program Flow: Branching
Using System Functions
Understanding Processing Order

Controlling Program Flow: Loops > Exiting from Loops Early

If so, a `do‑until` is the best choice. If instead, the value of an expression should be checked, then use the `while` loop.


Debugging

# Debugging

Rare is the case where a program works perfectly on the first try. Usually, a programmer must make numerous modifications to the original code in order to get the desired results. Programming bugs can be mistakes in syntax, typos, design errors, or a misunderstanding of certain language elements. This section is not intended to prevent mistakes, but rather to find and fix them.

## Compiler Errors

Of all the possible problems that a program can have, ones that cause the compiler to complain are perhaps the easiest to remedy. The reason is quite simple: the compiler reveals what the problem is and where in the program it is located. The only job is to recognize exactly what the compiler means and make the necessary changes.

The following list provides the most common causes of compiler errors.

- Missing a semi‑colon at the end of a statement
- Having a semi‑colon where it does not belong (e.g., before an opening brace of a compound statement)
- Trying to use a variable that has not been declared, or misspelling a variable
- Attempting to assign a value to an input variable (digital, analog, string, or buffer)
- Syntax errors

If multiple error messages are received when compiling the program, always work with the first one before attempting to fix the rest. Many times, a missing semi‑colon at the beginning of a program can confuse the compiler enough that it thinks there are many more errors. Fixing the first error may clear up the rest.

## Run‑time Errors

The term "run‑time error" refers to an error that is not caught by the compiler but causes the program to crash while it is running. For example, consider the following statement.

x = y / z;

The compiler passes by this statement in the program with no problem, as it should. This is a perfectly valid statement. However, if during run‑time the variable **z** contains **0** when this statement executes, this becomes an illegal operation. Although the control system is robust enough to catch most errors like this and the system should not crash, unexpected results may occur.

To determine if a run‑time error is occurring in your program, watch the status of the control system's computer port with a program such as the Viewport (available through SIMPL or Crestron VisionTools® Pro-e). An **Interrupt** message or some other error message can clue the user in to a problem. Locate the problem by strategically placing **Print** statements in the code. The **Print** statement is covered in the next section.

SIMPL Plus Tutorial
Debugging
TP Debugging


Debugging with Print()

## Debugging with Print()

The most powerful debugging tool for use with SIMPL+ is the **Print** function. This function allows the user to print out messages and variable contents during program execution. The data that is generated by the **Print** function is sent to the computer port of the control system, making it viewable using a terminal emulation program such as the Viewport tool that comes with SIMPL and VisionTools Pro.

The **Print** function is nearly identical to the **MakeString** function discussed in [Working with Data (Variables)]. The only difference between the two functions is that **MakeString** generates a formatted string into a string variable, while **Print** generates a formatted string and spits it out of the control system's computer port.

The syntax of **Print** is provided in the following example.

Print("\<specification string\>",\<variable list\>);

The **\<specification string\>** is a string, which determines what the output looks like. It can contain static text intermixed with format specifiers. A format specifier is a percentage sign (**%**) followed by a type character. For example, **%d** is a format specifier for a decimal value, and **%s** is the format specifier for a string. Consider this specific example.

INTEGER extension;\
STRING name[30];

PUSH print_me\
{\
extension = 275;\
name = "Joe Cool";\
Print("%s is at extension %d", name, extension);}

When this program is run and the digital input, **print_me**, goes high, the following text is output from the computer port:

Joe Cool is at extension 275

The **Print** statement works by replacing the format specifiers in the specification string with the value of the variables in the variable list. Notice that the order of the format specifiers must match the order of the variables in the list. In this example, the first format specifier encountered is **%s**, which corresponds to the string name. The next specifier is **%d**, which corresponds to the integer extension. If the variables in the list were reversed and the specification string kept the same, the output would be unpredictable because the system would try to print extension as a string and name as an integer.

Refer to the latest revision of the SIMPL+ Language Reference Guide for a complete listing of all available format specifiers for use with the **Print** and **MakeString**.

  [Working with Data (Variables)]: ../Working_With_Data/TP_Working-with-Data-(Variables).md

SIMPL Plus Tutorial
Debugging
TP Debugging
Debugging with Print()

Data Debugging INTEGER PUSH Print STRING Variables Working with

Locate the problem by strategically placing **Print** statements in the code. The **Print** statement is covered in the next section.


For Whom is this Guide Intended?

# For Whom is this Guide Intended?

This tutorial assumes the reader has at least a working knowledge of the SIMPL programming environment. This includes the ability to configure a new program (define the hardware), and to interconnect user-interfaces (e.g., a touch screen) and system outputs (e.g., a relay). Knowledge of the SIMPL logic symbols is not required, but is helpful in understanding some of the examples presented herein.

This guide is intended to be the complete SIMPL+ programming guide, appropriate for the beginning SIMPL+ programmer, or the expert programmer looking for a refresher course. This guide, along with The SIMPL+ Reference Manual should provide all the information needed for any SIMPL+ programmer.

SIMPL Plus Tutorial
For Whom is this Guide Intended
For Whom is this Guide Intended?


SIMPL_Plus_Tutorial/Operators,_Expressions_and_Statements/TP_Operators, Expressions, and Statements.md

Operators, Expressions, and Statements

# Operators, Expressions, and Statements

This sections deals with the core programming elements in SIMPL+.

## Operators

Operators take one or two operands and combine them in some way to produce a result. In SIMPL+ operators can be binary (takes two arguments) or unary (takes a single argument). For example, the + operator is binary (e.g., x + y), while the ‑ operator can be binary or unary (e.g., x ‑ y, or ‑x are valid). Most operators in SIMPL+ are binary. Notice that operands do not have to be simple constants or variables. Instead they can be complex expressions that result in an integer.

SIMPL+ operators can be classified into three categories: arithmetic, bitwise, and relational. The sections below describe each category briefly. For a complete list of operators and their function, consult the latest revision of the SIMPL+ Language Reference Guide.

### Arithmetic Operators

Arithmetic operators are used to perform basic mathematical functions on one or two variables. In all but one case, these operations make sense only for integer types (includes analog inputs and outputs). For example, to add two integers, `x` and `y`, together, use the addition operator `+`, as follows.

x + y

As mentioned in the previous paragraph, use these operators with integers in all but one case. The exception is the `+` operator when used with string variables. In this case the operator performs a concatenation instead of addition, which is very handy for generating complex strings from smaller parts. This is discussed in more detail later.

### Bitwise Operators

Arithmetic operators deal with integers as a whole. Bitwise operators treat the individual binary bits of a number independently. For example, the unary operator `NOT` simply negates each bit in number, while the `&` operator performs a binary “and” operation to each bit in the arguments (bit0 and-ed with bit0, bit1 with bit1, etc.).

### Relational Operators

Relational operators are used in expressions when it is necessary to relate (compare, equate, etc.) two values in some way (the exception to this is the unary operator `NOT`). When a comparison is done using a relational operator, the result is an integer, which represents `True` or `False`. In SIMPL+, `True` results equal `1` and `False` results equal `0`. In general, any non-zero value is considered by SIMPL+ to be `True`, while `False` is always `0`.

Typically, relational operators are used to help control the program flow. That is, test certain conditions and the result determines what happens next. This is discussed in more detail in [Controlling Program Flow: Branching].

TP Operators, Expressions, and Statements

Operators, Expressions, and Statements > Expressions


Expressions

## Expressions

As reading through the later parts of this guide, as well as the latest revision of the SIMPL+ Language Reference Guide, the term expression is mentioned in many places. For example, in describing the syntax of the `if‑else` construct, it may be described as the following:

if (expression1)\
{\
// code to execute}\
else if (expression2)\
{\
// code the execute}

In the above example, `expression1` and `expression2` can be any valid SIMPL+ expression. This section describes what is and what is not an expression.

An expression in SIMPL+ is anything that consists of operators and operands. Operators were discussed previously in this section, and operands are simply the things on which operators act. For example, refer to the following simple expression.

x + 5

In this expression the operator is the addition operator (`+`), and the operands are `x` and `5`. Expressions can contain constants, variables, and function calls in addition to operators. One expression may be made up of many smaller expressions. The following are all valid SIMPL+ expressions.

max(x,15)\
y \* x \<\< z\
a = 3\
(26 + byte(aString,i) mod z = 25

Expressions can range from the very simple to the very complex. Also note that the last two expressions contained an equal sign. It is very important to recognize that this operator can have two different meanings based upon where it is used. In the first example above, the equal sign can serve as an assignment operator (assign the value `3` to the variable `a`) or as an equivalency comparison operator (does the variable `a` equal `3`?). However, an expression cannot contain an assignment (it would then become a statement, discussed in [Operators, Expressions, and Statements]), so it is indeed recognized as a comparison operation. In the second case, the equal sign also serves as a equivalency comparison operator. Here there is no ambiguity since a value cannot be assigned into an expression (as opposed to a variable).

Expressions always evaluate to either an integer or a string. Refer to the following example.

x + 5               // this evaluates to an integer\
chr(i) + myString   // evaluates to a string\
a = 3               // evaluates to 1 if true, 0 if false\
b \< c               // evaluates to 1 if true, 0 if false

The last two expressions are comparisons. Comparison operations always result in a `true` or `false` value. In SIMPL+, `true` expressions result in a value of `1` and `false` expressions result in a value of `0`. Understanding this concept is key to performing decision making in SIMPL+. In reality, any expression that evaluates to a non‑zero value is considered `true`. This concept is discussed in [Controlling Program Flow: Branching] and [Controlling Program Flow: Loops].

Operators, Expressions, and Statements > Statements

That is, test certain conditions and the result determines what happens next. This is discussed in more detail in [Controlling Program Flow: Branching].


Statements

## Statements

Statements in SIMPL+ consist of function calls, expressions, assignments, or other instructions. Statements can be of two types: simple or complex. Simple statements end in a semicolon (**;**). Examples of simple statements are as follows:

x = MyInt / 10;                  // An assignment\
print("hello, world!\n");        // A function call\
checksum = atoi(MyString) + 5;   /\* Assignment using function calls and operators \*/

A complex statement is a collection of simple statements surrounded with curly braces (`{}`). An example of a complex statement would be as follows:

{ // start of a complex statement\
x = MyInt / 10;\
print("hello, world!\n");\
checksum = atoi(MyString) + 5;} // end of a complex statement

  [Controlling Program Flow: Branching]: ../Controlling_Program_Flow_Branching/TP_Controlling-Program-Flow-Branching.md
  [Operators, Expressions, and Statements]: #Statemen
  [Controlling Program Flow: Loops]: ../Controlling_Program_Flow_Loops/TP_Controlling-Program-Flow-Loops.md

Branching Controlling Flow Loops Program Statements

Controlling Program Flow: Branching
Controlling Program Flow: Loops

In reality, any expression that evaluates to a non‑zero value is considered `true`. This concept is discussed in [Controlling Program Flow: Branching] and [Controlling Program Flow: Loops].


Making it Work (Part 1)

# Making it Work

This section describes how to make the simple SIMPL+ program written in the last section work inside a Crestron control processor. As was mentioned earlier, SIMPL+ programs cannot run all by themselves. They must be enclosed inside a SIMPL wrapper. This section discusses how to set up this program in SIMPL.

Create a new SIMPL program and fill in the boxes in the **Program Header Information** window. Make sure to select the relevant information from the **Program ID Tag** and **Control Processor** dropboxes. Notice that only CNX‑series or newer control processors are compatible with SIMPL+. For this example, use the SIMPL Debugger to trigger the digital input. As a result, there is no need to define a touch screen or other user-interface device, although it is even better if one is available for testing.

After the system is configured, switch to the Program Manager by selecting **Project** \> **Program System** and make sure that the **Symbol Library** pane is visible on the left-hand side of the screen. Find the **User Modules** folder and open it. An icon representing the SIMPL+ program written in the previous section appears. Drag this icon into the **Logic** folder in the **Program View** pane. The SIMPL+ program now becomes just another symbol in the program.

Double‑click on the logic symbol to bring it into the **Detail View** window. It should have a single input, labeled **speak**. This corresponds directly to the declarations section of our SIMPL+ code, where only a single input and no outputs were defined. Define a signal for this input. The signal name here is not important, but for this example, call it **test_me**. Also note that if a user interface was defined in an earlier step, assign this same signal to a button press.

That’s it! The first program is complete. All that is left is to compile the whole thing, transfer it to the control processor, and test it. As in SIMPL, compile the program by clicking on the compile toolbar button or selecting **Project** \> **Convert/Compile**. The compile process automatically recognizes that there is a SIMPL+ module in the program and compiles it along with the SIMPL code (even though it was already compiled when it was saved; SIMPL always recompiles because it must link the modules together with the SIMPL program).

After compilation, transfer the program when prompted by SIMPL. Click **Yes** and the SIMPL code section is sent first (followed by the save permanent memory image). Once completed, the SIMPL+ program code is sent along with the SIMPL code base.

At this point a program has been loaded into the control system and is ready to be tested. Start SIMPL Debugger by opening Crestron Toolbox™ and selecting **Tools** \> **SIMPL Debugger**. Select the processor with the program that is running from the address bar in the bottom left corner of the Debugger window. Select **Yes** in the **Synchronize Signal** window.

SIMPL Plus Tutorial
Quick Start
Making it Work
Making it Work


Making it Work (Part 2)

The program is ready to be tested. Drive the signal to the high state by selecting it from the left-most pane and clicking the **Rising Edge** button from the **Stimulus** window above the signal tree. Driving the signal to the high state triggers the push event. In the right-hand pane, known as the **Trace Window**, the events that occur as a result of the button press display. The string **Hello world!** appears under the **Value** tab.

Click on the **Falling Edge** button to drive the signal low and trigger the release event. In the **Trace** window, the string **Crestron people make the difference** appears.

By clicking on the **Positive Pulse** button, both strings appear one after the other, since the push and release events are triggered in rapid succession.

NOTE: There are multiple ways to manually trigger the above events. Using the **Momentary Press** button in the **Stimulus** window, for instance, will trigger multiple events that display in the **Trace Window**. The various strings discussed above will all appear under the **Value** tab in as separate events.

Finally, what happened to the startup text “`I am born!`?” Remember that `Function Main` only runs on system startup and this occurred even before Debugger was started. Thus it was missed. To see it now, reboot the control processor by selecting **Options** \> **Reset Rack**.

In addition to the latest revision of the SIMPL+ Language Reference Guide, continue reading through this manual to learn more about how to program in SIMPL+.

Select the processor with the program that is running from the address bar in the bottom left corner of the Debugger window. Select **Yes** in the **Synchronize Signal** window.


Writing Your First SIMPL+ Program: "Hello World" (Part 1)

# Writing Your First SIMPL+ Program: "Hello World"

The best way to become acquainted with SIMPL+ is to write a simple program right off the bat. Although programs can be written in SIMPL+, it is important to understand that all control system I/O must be defined directly in SIMPL. This SIMPL program can be thought of as a shell in which the SIMPL+ modules are contained. This shell consists of hardware definitions at the very least, but in most cases also consists of raw SIMPL code. SIMPL+ program(s) appear as logic symbols in the overall SIMPL program.

Based on the fact that SIMPL+ programs can exist only inside this wrapper, it is necessary to create a skeleton SIMPL program before testing the program. This is covered in [Making It Work] section. For now, concentrate on writing the SIMPL+ code only.

Start creating a new SIMPL+ program while running SIMPL. Select **File \> New \> New SIMPL+ Module**.  The SIMPL+ programming environment appears. Instead of a blank window, a skeleton program filled with commented code shows up. This commented out code makes it easy to remember the language syntax and structure. Simply locate the necessary lines, uncomment them, and add the appropriate code. To uncomment a line of code, either remove the // that appears at the start of the line or remove the multi-line comment indicators /\*…\*/

SIMPL+ programs communicate with the SIMPL wrapper program via inputs and outputs. These inputs and outputs correspond to signals in the world of SIMPL and can be digital, analog, or serial signals (if these terms are unfamiliar, they are covered in more detail in [Input/Output Types]). For this first program, only a single digital input is defined. Find the line of code that says // DIGITAL_INPUT. Uncomment it and edit it so it looks like the following:

DIGITAL_INPUT speak;

This line defines the variable speak as the first digital input to the SIMPL+ program. Notice that most lines in SIMPL+ end in a semi-colon (;). To be precise, all statements end with a semi-colon. The definition of a statement in SIMPL+ can be found in the latest revision of the SIMPL+ Language Reference Guide..

Find the line of code that says // #PRINT_TO_TRACE and uncomment it so it looks like the following:

#PRINT_TO_TRACE

When a digital input goes from low to high, a push event is generated. To define a push event function for that signal, program this function to yield the desired actions. From the skeleton program, find the commented line of code that says PUSH input.. Uncomment the function block by removing the surrounding comment characters and edit it to read the following:

PUSH speak

{

Print("Hello World!\n");

}

This function causes the string Hello World! plus a carriage return and line feed to be sent out the control system computer port whenever the signal speak goes high. Notice the curly-braces ({}) surrounding the print statement above. In SIMPL+ these braces are used to group multiple statements into a compound statement. In the case of a function definition, always surround the contents of the function with these braces.

DIGITAL_INPUT First Hello PRINT_TO_TRACE PUSH Part Print Program SIMPL World Writing Your


Writing Your First SIMPL+ Program: "Hello World" (Part 2)

The next step is to add another event function, one that responds when a signal goes from high to low. This event is called a release event. From the skeleton program, find the line of code that says RELEASE input. Uncomment and edit it to read the following:

RELEASE speak

{

Print("Crestron people make the difference\n");

}

Finally, define what happens when the control system first boots up. This is accomplished using Function Main. Upon system startup, the program code defined in this function executes. Unless there are looping constructs (discussed in [Controlling Program Flow: Loops]) defined in this function, this code executes only one time for the life of the control system (or until it is rebooted). From the skeleton program, find the section of the program that says Function Main. Edit it to read the following.

Function Main()

{

Print("I am born!\n");

}

This causes the text I am born! to be sent out to the computer port only upon startup.

To save the file, from the menu, select **File \> Save**. Assign the name, My **first SIMPL+**. To compile the file, select **Build \> Save and Compile**. This command saves the code module, compiles it, and tells SIMPL how to present it to the SIMPL programmer. SIMPL+ version 2.0 requires that all SIMPL+ modules reside in the User SIMPL+ directory (this can be checked in SIMPL by selecting **Options \> Preferences...** and clicking on the **Directories** tab). In SIMPL+ 3.0 and later, SIMPL+ modules can also reside in the corresponding SIMPL Project Directory, where the SIMPL program also resides.

Each time the program is saved, an update log appears at the bottom of the screen. This log shows the results of the save, compile, and update process that just occurred. Review and become familiar with it. The window should display something similar to this code:

Compiling c:\Crestron\simpl\usrsplus\my first simpl+.usp...

Total Error(s): 0

Total Warning(s): 0

SIMPL+ file saved successfully

No errors found: SIMPL Windows Symbol Definition updated

This first SIMPL+ program is complete. The next section explains how to incorporate this program into the required SIMPL wrapper, and how to run and test it.

  [Making It Work]: Making_it_Work.md
  [Input/Output Types]: ../The_Structure_of_a_SIMPL_Plus_Program/TP_Structure-of-a-SIMPLPlus-Program.md#Inputs,
  [Controlling Program Flow: Loops]: ../Controlling_Program_Flow_Loops/TP_Controlling-Program-Flow-Loops.md

Controlling Error First Flow Hello Input Loops Main Making Output Part Print Program RELEASE SIMPL Types Warning Work World Writing

Making It Work
Input/Output Types
Controlling Program Flow: Loops

In SIMPL+ these braces are used to group multiple statements into a compound statement. In the case of a function definition, always surround the contents of the function with these braces.


The Structure of a SIMPL+ Program

# The Structure of a SIMPL+ Program

What are the different elements that make up a SIMPL+ program? This section provides an overview of the code structure, given in the typical order that they are used.

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
The Structure of a SIMPL+ Program

The Structure of a SIMPL+ Program > Compiler Directives


Compiler Directives (Part 1)

## Compiler Directives

Compiler directives should come at the beginning of the program, and they are used to provide explicit instructions to the compiler. As such, these elements are not part of the SIMPL+ language itself. These directives are distinguished from actual SIMPL+ code by preceding them with a pound sign (`#`).

Currently there are thirty compiler directives, nineteen of which are provided in the template file that is created when a new program is started. The compiler directives are as follows.

- **`#SYMBOL_NAME` ‑**Allows the user to specify the name that SIMPL uses for this module. If this directive is left out, the filename will be used by default.
- **`#HINT` ‑** Provides text that appears in the SIMPL status bar whenever the module icon is clicked on.
- **`#CATEGORY` ‑** (SIMPL+ 3.0 and later) Specifies the SIMPL symbol tree category number for this SIMPL+ module, which controls where the SIMPL+ module is listed in the symbol tree in Program Manager. Selecting **Edit** \> **Insert Category** from the menu will display a list of available categories to choose from and automatically insert the selected category in to the program module.
- **`#DEFAULT_VOLATILE` ‑** (SIMPL+ 3.0 and later) Specifies that all program variables will retain their values if hardware power is lost. If neither the **`#DEFAULT_VOLATILE`** nor **`#DEFAULT_NONVOLATILE`** are specified, the compiler will default all variables declared within the SIMPL+ module as nonvolatile.
- **`#DEFAULT_VOLATILE` ‑** (SIMPL+ 3.0 and later) Program variables will not retain their value if hardware power is lost.
- **`#HELP_BEGIN / #HELP_END` ‑** Allows online help to be entered for this module. This text appears when the user selects the module and presses F1 from within SIMPL.
- **`#DEFINE_CONSTANT` ‑** Allows constant numeric/string values to be assigned to alphanumeric names. This is extremely useful for writing changeable and readable code.

This last compiler directive deserves more discussion, since using constant definitions are a very important part of writing readable code. To illustrate this, examine the following example.

PUSH vcr_select\
{\
switcher_input = 3;\
switcher_output = 2; // video projector}\

PUSH dvd_select\
{\
switcher_input = 4;\
switcher_output = 2; // video projector}

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
Compiler Directives


Compiler Directives (Part 2)

In this example it should be clear that the value of the variable `switcher_input` is being set to `3` if the **VCR** button is pressed or `4` if the **DVD** button is pressed. In both cases the variable, `switcher_output` is set to `2`, which is the output connected to the video projector. Presumably, these variables would be used somewhere else in the program to generate a command string to control a switcher. Using numbers in a small and simple program like this still produces a relatively readable program. Even so, a couple of problems should become evident. For one thing, if the switcher configuration is changed, and the inputs and outputs are rearranged, the user must carefully go through the program and change all the appropriate values for the switcher input and output. Secondly, in a larger program this technique becomes very hard to read. After all, the number 3 has no intrinsic relationship to a VCR.

Examine the following equivalent program, which uses constant definitions in place of actual numbers.

#DEFINE_CONSTANT VCR_INPUT 3\
#DEFINE_CONSTANT DVD_INPUT 4\
#DEFINE_CONSTANT VPROJ_OUTPUT 2

PUSH vcr_select\
{\
switcher_input = VCR_INPUT;\
switcher_output = VPROJ_OUTPUT; // video projector}

PUSH dvd_select\
{\
switcher_input = DVD_INPUT;\
switcher_output = VPROJ_OUTPUT; // video projector}

Note the use of capital letters for the constant definitions. This is not required, but it makes it clear to see the difference between variables and constants when reading through a program (but of course is not useful if all caps are used for the rest of the program). Not only is this version of the program easier to read, even for a small example, but it is obvious that changing a numeric value in one place (the `#DEFINE_CONSTANT`) can affect the value everywhere in the program.

Compiler DEFINE_CONSTANT Directives PUSH Part

To illustrate this, examine the following example. PUSH vcr_select\
{\
switcher_input = 3;\
switcher_output = 2; // video projector}\

PUSH dvd_select\
{\
switcher_input = 4;\
switcher_output = 2; // video projector}


Include Libraries

## Include Libraries

Libraries are a way of grouping common functions into one source file to enable modularity and reusability of source code. Libraries are different from modules in that they do not contain a starting point (`Function Main`), and cannot interact with the control system (through I/O signals and events). Libraries can include other libraries, but cannot include a SIMPL+ module. Only functions and defined constants are allowed to be declared and defined within libraries. Global variable declarations are not allowed. Functions, however, can contain local variables. Other advantages are:

1.  Modularity. SIMPL+ programs can grow to be large and can be better organized by taking sections of code and placing them into a **User‑Library**. It is best to create libraries that contain sets of related functions. For example, a library might be created that contains only functions that perform certain math related functions. Another library might be created that contains functions performing special string parsing routines.
2.  Reusability. As modules are written, it is common for SIMPL+ modules to need pieces of functionality that were previously written in other modules. These common and repeatedly portions of code can be extracted and placed into one or more libraries. Once placed into a library, one or more SIMPL+ modules can include and make use of them.

SIMPL+ modules include libraries using the following syntax:

#USER_LIBRARY “\<library_name\>”\
#CRESTRON_LIBRARY “\<library_name\>”

Note that `library_name` is the name of the library without the file extension. **User‑Libraries** are libraries that the end user writes. These can exist either in the SIMPL+ module’s project directory or in the User SIMPL+ directory (set in SIMPL).

**Crestron‑Libraries** are provided from Crestron and are contained within the Crestron Database.

## Variable Declarations

Variables can be thought of as storage areas to keep data. When writing all but the most basic of programs, users need to use variables to store values.

Any variable used in a SIMPL+ program must be declared before it is used. This also tells the operating system how much space must be reserved to hold the values of these variables. This section describes the different types of variables in SIMPL+ and how to define them.

.

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
Include Libraries

The Structure of a SIMPL+ Program > Variable Declarations > Inputs, Outputs, and Parameters

This is not required, but it makes it clear to see the difference between variables and constants when reading through a program (but of course is not useful if all caps are used for the rest of the program). Not only is this version of the program easier to read, even for a small example, but it is obvious that changing a numeric value in one place (the `#DEFINE_CONSTANT`) can affect the value everywhere in the program.


Inputs, Outputs, and Parameters

### Inputs, Outputs, and Parameters

SIMPL+ programs communicate with the SIMPL program in which they are placed through input and output variables and through parameter values. This is similar in concept to the Define Arguments symbol used in SIMPL macros. Input variables can be of three types: digital, analog, and string types. These correspond directly to the same signal types in SIMPL and the buffer input, which is a special case of the string input. Output variables can only be of the digital, analog, or string variety.

Input variables are declared using the following syntax.

DIGITAL_INPUT \<dinput1\>,\<dinput2\>,…\<dinputn\>;\
ANALOG_INPUT \<ainput1\>,\<ainput2\>,…\<ainputn\>;\
STRING_INPUT \<sinput1\>[size],\<sinput2\>[size],...\<sinputn\>[size];\
BUFFER_INPUT \<binput1\>[size],\<binput2\>[size],...\<binputn\>[size];

Note: For more information on the `buffer_input`, refer to [Working with Strings].

Digital and analog output variables are declared in the same way, except the word input is replaced with output, as shown below. String output variables do not include a size value. There is no output version of the buffer variable.

DIGITAL_OUTPUT \<doutput1\>,\<doutput2\>,…\<doutputn\>;\
ANALOG_OUTPUT \<aoutput1\>,\<aoutput2\>,…\<aoutputn\>;\
STRING_OUTPUT \<soutput1\>,\<soutput2\>,…\<soutputn\>;

The inputs and outputs declared in this way govern the appearance of the SIMPL+ symbols that are presented via SIMPL. The order of the signal declarations is important only within signal types; in SIMPL, digital signals always appear at the top of the list, followed by analogs, and then serials.

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
Inputs, Outputs, and Parameters

The Structure of a SIMPL+ Program > Variable Declarations > \

This section describes the different types of variables in SIMPL+ and how to define them. .


### \
Variables

In addition to the input and output variables described in the last section, the user can define and use variables that are only seen by the SIMPL+ program. That is, the SIMPL program, which holds this module has no knowledge of these variables. In addition, any other SIMPL+ modules that are included in the SIMPL program would not have access to these variables.

[Working with Data (Variables)] discusses variables in much more detail. For now, understand how to declare them. Declaring variables tells the SIMPL+ compiler how much memory to put aside to hold the workable data.

These variable declarations are very similar to input/output declarations. However, instead of digital, analog, and serial (string and buffer) types, integer and string variables are also available with the `INTEGER` and `STRING` datatype. Integers are 16 bit quantities. For the 2‑series and 3‑series control systems, 32 bit quantities are supported with the `LONG_INTEGER` datatype. Both `INTEGER` and `LONG_INTEGER` are treated as unsigned values. Signed versions for both of these datatypes are available by using the `SIGNED_INTEGER` and `SIGNED_LONG_INTEGER` datatypes. The following example illustrates how each of these datatypes can be used within a program module:

INTEGER intA, intB, intC;\
STRING stringA[10], stringB[20];\
LONG_INTEGER longintA, longIntB;\
SIGNED_INTEGER sintA, sintB;\
SIGNED_LONG_INTEGER slongIntA;

It is important to realize that all variables declared in this manner are non‑volatile. That is, they remember their values when the control system reinitializes or even if the power is shut off and then turned back on. Since input/output variables are attached directly to signals defined in the SIMPL program, they do not have this property unless the signals they are connected to are explicitly made non‑volatile through the use of special symbols.

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
\

The Structure of a SIMPL+ Program > Variable Declarations > Structures

DIGITAL_OUTPUT \<doutput1\>,\<doutput2\>,…\<doutputn\>;\
ANALOG_OUTPUT \<aoutput1\>,\<aoutput2\>,…\<aoutputn\>;\
STRING_OUTPUT \<soutput1\>,\<soutput2\>,…\<soutputn\>;

The inputs and outputs declared in this way govern the appearance of the SIMPL+ symbols that are presented via SIMPL. The order of the signal declarations is important only within signal types; in SIMPL, digital signals always appear at the top of the list, followed by analogs, and then serials.


Structures

### Structures

Sometimes sets of data are needed rather than individual pieces. Variables store a piece of data, but are not related to other variables in any way. Structures are used to group individual pieces of data together to form a related set. Before structures can be used, a structure definition must be defined. Defining a structure is really defining a custom datatype (such as `STRING`s and `INTEGER`s). Once this new type (the `STRUCTURE`) is defined, variables of that type can be declared. The following example illustrates how a structure can be defined and used within a program module:

STRUCTURE PhoneBookEntry\
{\
STRING Names[50];\
STRING Address[100];\
STRING PhoneNumber[20];\
INTEGER Age;};\

PhoneBookEntry OneEntry;\
PhoneBookEntry Entry[500];

To access a variable within a structure, the structure’s declared variable name is used, followed by a period (also known as the dot or dot operator), followed by the structure member variable name. For example:

PUSH BUTTON\
{\
OneEntry.Names="David";\
OneEntry.Address="100 Main Street";\
OneEntry.PhoneNumber="800 555‑5555";\
OneEntry.Age="30";

Entry[5].Names="Andrew";\
Entry[5].Address="15 Volvo Drive";\
Entry[5].PhoneNumber="201 767‑3400";\
Entry[5].Age="23";}

\
User-Defined Functions
------------------------------------------

In programming, it is common to reuse the same code over and over again. For example, when writing a program to generate strings (to control a device), there may be a need to calculate a checksum byte. Once the code to calculate this byte is formulated, paste it in to the program after each instance where a command string is created.

Note: The term `checksum` byte is commonly used in serial communications to represent a byte (or bytes) that is appended to a command string. This byte is calculated from the other characters in the string using some specified algorithm. `checksum` bytes are used to provide error-checking when communicating between devices.

This technique has many flaws. First, the program can grow unnecessarily large and become hard to manage and debug. Second, if there is a need to change the code, it must be changed every place it was used, which is time consuming and error prone.

The solution is to create user‑defined functions to perform common tasks. A user‑defined function is very similar to a built‑in function like `Date` or `MakeString`, with some important exceptions.

To invoke a user‑defined function, use the following syntax:

CALL MyUserFunction();

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
Structures

INTEGER MyUserFunction PUSH STRING STRUCTURE Structures

The Structure of a SIMPL+ Program > Event Functions

That is, they remember their values when the control system reinitializes or even if the power is shut off and then turned back on. Since input/output variables are attached directly to signals defined in the SIMPL program, they do not have this property unless the signals they are connected to are explicitly made non‑volatile through the use of special symbols.


Event Functions

## Event Functions

Event functions make up the heart of most SIMPL+ programs. Since a well-designed control system is event‑driven in nature, most code is activated in response to certain events when they occur. Event functions allow the user to execute code in response to some change that has occurred to one or more of the input signals feeding the SIMPL+ module from the SIMPL program.

Two things must be realized about event functions. They can be used with input variables only (not with locally defined variables). Also, they are only triggered by the operating system at the appropriate time (that is, they cannot be called manually by the programmer).

Like everything else in the control system, event functions are multi‑tasking. That is, an event can be triggered even if another event in the same SIMPL+ module is already processing. As described in [Understanding Processing Order], this only happens if events are triggered on the same logic wave, or if one event function has caused a task switch.

The structure of an event function is as follows.

event_type \<input list\>\
{\
\<statements\>}

In SIMPL+ there are three basic event types that can occur: Push, Release, and Change. In addition to these three is a fourth type simply called Event. These event types are discussed in the following subsections.

### \
Push and Release Events

Push and Release events are valid only for `DIGITAL_INPUT` variables. The Push event is triggered when the corresponding digital input goes from a low to a high state (positive‑ or rising‑edge). The Release event occurs when the signal goes from a high to a low (negative‑ or falling‑edge). For example, the following code sends a string to a camera unit to pan left when the left button is pressed and then send a stop command when the button is released.

DIGITAL_INPUT cam_up, cam_down, cam_left, cam_right;\
STRING_OUTPUT camera_command;

PUSH cam_left\
{\
camera_command = "MOVE LEFT";}

RELEASE cam_left\
{\
camera_command = "STOP";}

Note: This example assumes that the camera unit being controlled continues to move in a given direction until a stop command is issued. Some devices function this way, but others do not.

### \
Change Events

Change events can be triggered by digital, analog, string, or buffer inputs. Anytime the corresponding signal changes its value, the Change event will be triggered. For digital signals, this means that the event will trigger on both the rising and falling edges (push and release). For buffer inputs, this event triggers any time another character is added to the buffer.

The following example sends a command to a CD player to switch to a different disc whenever the analog input `disc_number` changes value.

ANALOG_INPUT disc_number;\
STRING_OUTPUT CD_command;

CHANGE disc_number\
{\
CD_command = "GOTO DISC " + itoa(disc_number);}

This program uses the `itoa` function to convert the analog value in `disc_number` into a string value which can be concatenated onto `CD_command`. The string concatenation operator (`+`) and system functions (i.e., `itoa`) are discussed in later sections of the manual and in the latest revision of the SIMPL+ Language Reference Guide.

SIMPL Plus Tutorial
The Structure of a SIMPL Plus Program
TP Structure-of-a-SIMPLPlus-Program
Event Functions

ANALOG_INPUT CHANGE DIGITAL_INPUT Event Functions LEFT PUSH RELEASE STRING_OUTPUT

The Structure of a SIMPL+ Program > Event Functions > \

A user‑defined function is very similar to a built‑in function like `Date` or `MakeString`, with some important exceptions. To invoke a user‑defined function, use the following syntax:

CALL MyUserFunction();


### \
Compound Events

Sometimes it is desired to have the same (or similar) action occur when any of a number of events occur. For example, there may be a need to generate a switcher command string each time any of a group of **output** buttons are pressed.

Compound events can be created in two ways. One way is to provide a list of input signals separated by commas in the event function declaration. Refer to the following example.

PUSH button1, button2, button3\
{\
\<statements\>}

A second form of compound event occurs when combining different types of events into a single function. For example, there may be a need to execute some code when a button is pushed or the value of an analog signal changes. To accomplish this, stack the event function declarations, as follows.

CHANGE output_value\
PUSH button1, button2\
{\
\<statements\>}

A useful feature of SIMPL+ event functions is that a single input can have more than one event function defined for it. This makes it possible to write one event function for a specific input only and another event function for a group of inputs. Refer to the following example.

PUSH button1\
{ // code here only runs when\
  // button1 goes high\
}

PUSH button1, button2, button3\
{ // this code runs when any of\
  // these inputs goes high\
}

ANALOG_INPUT disc_number;\
STRING_OUTPUT CD_command;

CHANGE disc_number\
{\
CD_command = "GOTO DISC " + itoa(disc_number);}

This program uses the `itoa` function to convert the analog value in `disc_number` into a string value which can be concatenated onto `CD_command`. The string concatenation operator (`+`) and system functions (i.e., `itoa`) are discussed in later sections of the manual and in the latest revision of the SIMPL+ Language Reference Guide.