# SIMPL+ Programming Language Reference # Version: 1.0.0 > Complete reference documentation for Crestron SIMPL+ programming language ================================================================================ -------------------------------------------------------------------------------- ## Allowable Ranges for 2 Series Numeric Formats -------------------------------------------------------------------------------- # Allowable Ranges for 2 Series Numeric Formats Percent (Unsigned, 16b):  0.000% to 100%.  (3 decimal places of precision). Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Percent (Signed, 16b):  -50% to 49.999% (3 decimal places of precision). Legal for SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER Decimal (Unsigned, 16b):  0d to 65535d Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Decimal (Signed, 16b):  -32768d to 32767d Legal for SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER Decimal (Unsigned, 32b): 0d to 4294967295d Legal for LONG_INTEGER_PARAMETER Decimal (Signed, 32b):  -2147483648d to 2147483647d Legal for SIGNED_LONG_INTEGER_PARAMETER Ticks (Unsigned, 16b):  0t to 65535t Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Ticks (Signed, 16b):  SIGNED TIME NOT LEGAL (i.e. can't allow -5t) Ticks (Unsigned, 32b): 0t to 4294967295t Legal for LONG_INTEGER_PARAMETER Ticks (Signed, 32b):  SIGNED TIME NOT LEGAL (i.e. can't allow -5t) Hex (Unsigned, 16b):  0h to FFFFh Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Hex (Signed, 16b):  -8000h to 7FFFh Legal for SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER Hex (Unsigned, 32b):  0h to FFFFFFFFh Legal for LONG_INTEGER_PARAMETER Hex (Signed, 32b):  -80000000h to 7FFFFFFFh Legal for SIGNED_LONG_INTEGER_PARAMETER Time (Unsigned, 16b):  0s to 655.35s Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Time (Signed, 16b):  SIGNED TIME NOT LEGAL (i.e. can't allow -5s) Time (Unsigned, 32b):  0s to 4294967295s Legal for LONG_INTEGER_PARAMETER Time (Signed, 32b):  SIGNED TIME NOT LEGAL (i.e. can't allow -5s) Character (Unsigned, 16b):  any single typeable character between '', i.e. 'a'. Legal for INTEGER_PARAMETER, LONG_INTEGER_PARAMETER Character (Signed, 16b):  NOT LEGAL (i.e. can't allow -'a') Character (Unsigned, 32b):  NOT LEGAL Character (Signed, 32):  NOT LEGAL Note for time, the following formats are valid:    HH.MM.SS.HS    MM.SS.HS    SS.HS    SS    .HS Note that any of the above values don't need to be padded with leading 0's, so that    02.03.04.5s = 2.3.4.5s Padding HS with leading 0's makes it a different # since it's a fraction! For example,    2.25.36.08s (HH.MM.SS.HS)    145.36.08s  (MM.SS.HS)    8736.08s    (SS.HS) -------------------------------------------------------------------------------- ## Examples -------------------------------------------------------------------------------- # Examples This topic is provided to show cases of what is valid & invalid when declaring parameter properties.  Legal values for bounds/list elements/default values/etc. for parameter properties can be found in [Allowable Ranges for 2 Series Numeric Formats], Example 1: INTEGER_PARAMETER val; By itself, an integer parameter is unsigned and may hold a value of 0d to 65535d in SIMPL.  If the programmer tries to enter a value of (for example) 70000d, SIMPL will reject it. Example 2: INTEGER_PARAMETER val; #BEGIN_PARAMETER_PROPERTIES val     propValidUnits=unitDecimal|unitHex;     propDefaultUnit=unitPercent; #END_PARAMETER_PROPERTIES This is incorrect because the propDefaultUnit is not contained in propValidUnits. Example 3: INTEGER_PARAMETER val; #BEGIN_PARAMETER_PROPERTIES val     propValidUnits=unitDecimal|unitHex;     propDefaultUnit=unitDecimal;     propDefaultValue=25%; #END_PARAMETER_PROPERTIES This is incorrect because the propDefaultValue is not contained in the propValidUnits. Example 4: INTEGER_PARAMETER val; LONG_INTEGER_PARAMETER val2; #BEGIN_PARAMETER_PROPERTIES val, val2     propValidUnits=unitDecimal|unitHex;     propDefaultUnit=unitDecimal;     propDefaultValue=70000d #END_PARAMETER_PROPERTIES Example 5: This is incorrect because 70000d is not a legal value for an INTEGER_PARAMETER.  However, it is legal for the LONG_INTEGER_PARAMETER. INTEGER_PARAMETER val; #BEGIN_PARAMETER_PROPERTIES val     propValidUnits=unitDecimal|unitHex;     propDefaultUnit=unitDecimal;     propList={5d, "Value1"},{6d, "Value2"}; #END_PARAMETER_PROPERTIES This is a valid, legal case.  SIMPL will only let the programmer pick "Value1 [5d]" or "Value2 [6d]" from the dropdown. Example 6: INTEGER_PARAMETER val; #BEGIN_PARAMETER_PROPERTIES val     propValidUnits=unitDecimal|unitHex;     propDefaultUnit=unitDecimal;     propBounds=0x25,0x30; #END_PARAMETER_PROPERTIES This is legal since the propBounds specifies a legal unit based on the propValidUnits list and the upper & lower bounds are legal for an INTEGER_PARAMETER.   This example will restrict the the programmer using the module to typing in any value between 25h and 30h, whether they specify it in decimal or hex.  The default notation is decimal if they do not type in a unit. Example 7: INTEGER_PARAMETER val; #BEGIN_PARAMETER_PROPERTIES val     propDefaultUnit=unitTime;     propDefaultValue=8d; #END_PARAMETER_PROPERTIES Although this does not list a propValidUnits, it is still legal because ALL units are considered valid when no propValidUnits is entered.  The default value when the symbol is dropped into SIMPL is 8d, however, when any value is entered without explicit units, the units are assumed to be "s".  (i.e. entering 5 and hitting ENTER will change to 5s).  This example may not be very practical, but it is legal. [Allowable Ranges for 2 Series Numeric Formats]: Allowable_Ranges_for_2_Series_Numeric_Formats.md -------------------------------------------------------------------------------- ## General Information > Comments -------------------------------------------------------------------------------- # Comments It is beneficial to comment code to make it more readable and for documentation. Comments do not exist in any form after code generation and are not required. SIMPL+ has two styles of comments, single line and block comments. Single line comments start with the characters //. The rest of the line (until a carriage return) is considered a comment. If they occur within a quoted string, such as in PRINT, they are NOT treated as comment characters, but rather as two backslash (Hex 2F) characters. Examples: PRINT("Hello, World!\n");  // This stuff is a comment. PRINT("hello, // world!\n"); // This stuff is a comment,                              // but the string actually                              // printed is hello, // world. The second form of comment characters are the block comments. /\* starts a block comment and \*/ ends a block comment. This is useful for commenting out large sections of code or writing large sections of documentation. Note that nested comments are not supported. Also, if /\* or \*/ appear inside of a quoted string such as in an PRINT statement, they are not considered comments but part of the string. Examples:     /\*     This     is     all     a comment!     \*/     PUSH Trig     {       // code that does something.     } -------------------------------------------------------------------------------- ## General Information > Conventions Used -------------------------------------------------------------------------------- # Conventions Used Variable names are placed in \<\> when discussing syntax. For example, PUSH \. Optional parameters are placed in [ ]. For example, when a list has many parameters, it would be described as \[, \...] When discussing array notation, [ ] is used for array subscripting and is not used to mark optional code. Examples are placed in a Computer Style font, i.e. MyVariable = ATOI(SomeOtherVariable); -------------------------------------------------------------------------------- ## General Information > Index > Introduction -------------------------------------------------------------------------------- # Introduction                              SIMPL+ is a language extension that enhances SIMPL by using a procedural "C-like" language to code elements of the program that were difficult, or impossible, with SIMPL alone. This help system provides specific information about the SIMPL+ language syntax, and can be used as a reference manual. For a tutorial on SIMPL+ programming, consult the Crestron SIMPL+ Software Programming Guide (Doc. 5789A). The latest version of the guide can be obtained from the Product Manuals area of the Crestron website ([www.crestron.com]). You can also click [here] to open the programming guide from this help file. A SIMPL+ program is a module that directly interacts with the control system. To interact with the control system, a module must contain a few essential elements. The first element is a starting point.  A starting point is needed for two reasons. First, it serves as a convenient place to initialize any global variables that are declared within the module.  Second, any functionality that the module needs to perform on it’s own (instead of being triggered though an event), can be instantiated here. Another element is event processing. In order for a SIMPL+ module and a control system to interact, they must be able to send and receive signals to and from one another.  Input and output (I/O) signals are declared within the module and are then tied directly to the control system.  Input signals are sent from the control system and are received within the SIMPL+ module.  Output signals are sent from the SIMPL+ module to the control system.  Events are functions that are triggered through input signals from the control system.   I/O signals can be either digital, analog or serial and are declared within the SIMPL+ module. Events tell the SIMPL+ module that something has changed within the control system and allows the module to perform any action accordingly. NOTE:     In some cases the version of the SIMPL+ Cross Compiler Include file can cause unexpected return values. If you experience this phenomenon check the Cross Compiler Include file version by opening Help | About SIMPL+ . . . in the SIMPL+ Editor. hv.3.03.03; 23.5.18 [www.crestron.com]: http://www.crestron.com [here]: ../SIMPL_Plus_Tutorial/What_is_SIMPL_Plus_.md -------------------------------------------------------------------------------- ## General Information > Legal-Information > Legal Information -------------------------------------------------------------------------------- # Legal Information Crestron Electronics, Inc. Last Updated: 08 March 2023 **Description** Crestron Software Development Tools (“Software Tools”) may incorporate, access, include or utilize software libraries or products not written by Crestron, but instead, provided by third parties (“Third Party Software”). Third Party Software may be subject to open source and third-party licensing terms. The license terms associated with open source and Third-Party Software require that Crestron acknowledges those third parties and third-party licensing terms (“Third-Party Software Notices”). These Third-Party Software Notices are incorporated into by reference and apply to all products installed by Crestron MasterInstaller and each Crestron Software Tools software. Not all products contain the same Third Party Software or portions thereof. Crestron’s “MasterInstaller” Software contains virtually all the Software Tools that are used by Crestron authorized dealers and programmers to design a custom Crestron solution. Once MasterInstaller is loaded and run on a target personal computer (PC) or other device, it will automatically contact the Crestron website to get all updates to each development tool and download and install the needed Crestron software in the background. IMPORTANT: BY INSTALLING AND/OR USING THIS CRESTRON MASTERINSTALLER SOFTWARE, OR ANY CRESTRON SOFTWARE DEVELOPMENT TOOL INDIVIDUALLY, YOU ARE AGREEING TO BE BOUND BY THE TERMS CONTAINED IN THE FOLLOWING: 1. [Crestron Software End-User License Agreement\ \ ] 2. [Software Development Tools License Agreement\ \ ] 3. [Third Party Software Notices\ \ ] 4. [Crestron Privacy Statement Regarding Internet Data Collection\ \ ] 5. [Trademark Acknowledgments\ \ ] NOTICE: CERTAIN CRESTRON SOFTWARE TOOLS INCORPORATE FLASH® PLAYER SOFTWARE , DEVELOPED BY ADOBE INC., TO RENDER TEXT, VECTOR GRAPHICS, AND RASTER GRAPHICS IN ORDER TO PROVIDE ANIMATIONS AND DEVELOP END-USER APPLICATIONS FOR CRESTRON PRODUCTS. THE TERMS UNDER WHICH CRESTRON HAS LICENSED FLASH® PLAYER HAVE CHANGED. FLASH PLAYER MAY NO LONGER BE DISTRIBUTED IN THE PEOPLE’S REPUBLIC OF CHINA, INCLUDING BUT NOT LIMITED TO CRESTRON DEALERS, INSTALLERS, PROGRAMMERS, AND SERVICE PROVIDERS. [Crestron Software End-User License Agreement\ \ ]: https://www.crestron.com/Legal/software-license-agreement/Crestron-Software-End-User-License-Agreement "https://www.crestron.com/Legal/software-license-agreement/Crestron-Software-End-User-License-Agreement" [Software Development Tools License Agreement\ \ ]: https://www.crestron.com/Legal/software-license-agreement/MasterInstaller-and-SW-Tools-Installation-Agree "https://www.crestron.com/Legal/software-license-agreement/MasterInstaller-and-SW-Tools-Installation-Agree" [Third Party Software Notices\ \ ]: https://www.crestron.com/Legal/software-license-agreement/Third-Party-Software-Notices-for-Crestron-Tools "https://www.crestron.com/Legal/software-license-agreement/Third-Party-Software-Notices-for-Crestron-Tools" [Crestron Privacy Statement Regarding Internet Data Collection\ \ ]: https://www.crestron.com/Legal/Privacy-Policy "https://www.crestron.com/Legal/Privacy-Policy" [Trademark Acknowledgments\ \ ]: https://www.crestron.com/Legal/software-license-agreement/Trademark-Acknowledgement-Notices "https://www.crestron.com/Legal/software-license-agreement/Trademark-Acknowledgement-Notices" -------------------------------------------------------------------------------- ## General Information > Relative Path Names for Files -------------------------------------------------------------------------------- # Relative Path Names for Files Your current working directory is reset to the default ("/" or root) whenever "StartFileOperations" is performed. It is changed only by "SetCurrentDirectory".   File names can consist of full path names or relative path names. Full path names have the same restrictions as DOS file names in characters and format, with maximum length of 256 characters. Relative path names do not begin with a "\\ and start from the current working directory. -------------------------------------------------------------------------------- ## General Information > Variable Names -------------------------------------------------------------------------------- # Variable Names Variable names in SIMPL+ may be up to 30 characters long and may not contain any of the operators specified in the "Operators" section. Valid characters in a variable name are a-z, A-Z, 0-9, #, _, and $ but may not begin with 0-9. Variable names may not duplicate existing function or keyword names. Variable names in SIMPL+ are not case sensitive. For example, declaring a variable "joe" can be used as "jOe" or "JOE" or any variation of case. NOTE:  Version 3.00.12 users: variable names may be 120 characters for 2-Series systems. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > Arrays -------------------------------------------------------------------------------- # Arrays Various one and two dimensional arrays are supported. All input and output arrays are 1-based, meaning that the first element has index 1, not 0. Internal variables are 0-based, meaning that the first element has index 0. In both cases, the index of the last element is the same as the dimension of the array. Do not confuse the declaration of the length of STRINGs with the declaration of arrays. E.g., STRING s$[32] is a single string of length 32, and STRING ManyS$[10][32] is an array of 11 strings of length 32 each. You must use the BYTE function to access the character at a particular position in a string, but you can use the array index to access a particular string in an array of strings. Positions in a string are 1-based. See the discussion of Minimum Size Arrays in [Declaration Overview]. One dimensional arrays of the following types are supported: DIGITAL_INPUT DIGITAL_OUTPUT ANALOG_INPUT ANALOG_OUTPUT STRING_OUTPUT BUFFER_OUTPUT STRUCTURES One dimensional arrays of strings are also supported, although since the declaration also contains a string length, it looks like a 2-dimensional array: STRING_INPUT BUFFER_INPUT STRING One and two dimensional arrays of the following types are supported: INTEGER LONG_INTEGER SIGNED_INTEGER SIGNED_LONG_INTEGER Examples: | | | |----|----| | Declaration | Meaning | | DIGITAL_INPUT in[10]; | 10 digital inputs, in[1] to in[10] | | INTEGER MyArray[10][20]; | 11 rows by 21 columns of data, from MyArray[0][0] to MyArray[10][20] | | STRING PhoneNumbers[100][32]; | 101 strings that are a maximum of 32 characters long, e.g. PhoneNumbers[0] to PhoneNumbers[100] | | STRING_INPUT in$[32]; | One input string called in$ that is 32 characters long. | | STRING_OUTPUT out$[10]; | Ten output strings, out$1 to out$[10]. Their length does not have to be specified. | | STRING_INPUT in$[5][32]; | Five input strings, in$[1] to in$[5] that are 32 characters long. | | \ myStruct[10]; | 11 structure elements from myStruct[0] to myStruct[10]. | NOTE: An element of an integer array is not accepted where a function requires an integer. [Declaration Overview]: ../Declarations/Declarations_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > GetLastModifiedArrayIndex -------------------------------------------------------------------------------- # GetLastModifiedArrayIndex Name: GetLastModifiedArrayIndex Syntax:     INTEGER GetLastModifiedArrayIndex (); Description: Determines the specific index number of an input list array that has changed. ANALOG_INPUT, BUFFER_INPUT, DIGITAL_INPUT, and STRING_INPUT arrays are subject to be used in CHANGE, PUSH, and RELEASE statements, but only the overall array can be specified in the statement, not an individual element. In order to find out what element has been modified (and hence caused the activation of the CHANGE, PUSH, or RELEASE), GETLASTMODIFIEDARRAYINDEX is used. NOTE:  To use GETLASTMODIFIEDARRAYINDEX, only one array may be used in a single CHANGE, PUSH, or RELEASE statement. If more than one element of the array changes at the same time, multiple events are run. For example, if D[10] is a DIGITAL_INPUT array that is subject to a PUSH event, and D[1] and D[2] change at the same time, the PUSH is first run where D[1] changes and GETLASTMODIFIEDARRAYINDEX returns 1, then the PUSH is run again where D[2] changes and GETLASTMODIFIEDARRAYINDEX returns 2. NOTE:  Using GetLastModifiedArrayIndex OUTSIDE of an event (PUSH, RELEASE, CHANGE or EVENT) may return an index to an ambiguous signal if more than one input array is declared within the program.  Therefore, do not use this function if more than one input signal array is declared within the program, unless you use it within one of the event statements. Return Value: The element of the array that has changed. Example 1, Correct Use:     DIGITAL_INPUT LIGHT_SCENES[10], MORE_LIGHT_SCENES[10};     DIGITAL_OUTPUT INTERLOCKED_LIGHT_SCENES[10];     INTEGER I;     PUSH LIGHT_SCENES     {         FOR(I=1 to 10) INTERLOCKED_LIGHT_SCENES[I] = 0;       ProcessLogic();       INTERLOCKED_LIGHT_SCENES[GetLastModifiedArrayIndex()] = 1;     } Example 2, Incorrect Use: DIGITAL_INPUT LIGHT_SCENES[10]; DIGITAL_OUTPUT INTERLOCKED_LIGHT_SCENES[10]; INTEGER I; PUSH LIGHT_SCENES,MORE_LIGHT_SCENES[10] {//this PUSH statement will be called twice (once for LIGHT_SCENES and once for MORE_LIGHT_SCENES)   FOR(I=1 to 10) INTERLOCKED_LIGHT_SCENES[I]=0 ProcessLogic(); INTERLOCKED_LIGHT_SCENES[GetLastModifiedArrayIndex()] = 1;     } } In this example, when one input element changes, all the output elements are set to 0 and then the output level corresponding to the changed input level is set to 1. This mimics the functionality of the Interlock symbol in SIMPL. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > GetNumArrayCols -------------------------------------------------------------------------------- # GetNumArrayCols Name: GetNumArrayCols Syntax:     INTEGER GetNumArrayCols(STRING | INTEGER Description: Finds the number of columns in a two-dimensional array or the size of the array for a one-dimensional array. Parameters: ARRAY_NAME is the array as determined by the size. Return Value: For the data types in the table after this paragraph, the return value of GetNumArrayCols is shown. | | | |---------------------------------------------|--------------| | DATA TYPE | RETURN VALUE | | ANALOG INPUT X [size] | Size | | ANALOG INPUT X [size] | Size | | DIGITAL INPUT X [size] | Size | | DIGITAL OUTPUT X [size] | Size | | STRING INPUT X [size] | Chars | | STRING INPUT X [size] [chars] | Chars | | STRING OUTPUT X [size] | Size | | STRING X [chars] | Chars | | STRING X [size] [chars] | Chars | | INTEGER X [size] | Size | | INTEGER X [size 1] [size 2] | Size2 | | SIGNED_INTEGER X [size] | Size | | SIGNED_INTEGER X [size 1] [size 2] | Size2 | | SIGNED_LONG_INTEGER X [size] | Size | | SIGNED_LONG_INTEGER X [size 1] [size 2] | Size2 | | BUFFER INPUT X [chars] | Chars | | BUFFER INPUT X [size] [chars] | Chars | Example:     DIGITAL_INPUT TEST;     INTEGER My_Array[10][20];     PUSH TEST     {       PRINT("Columns = %d\n", GetNumArrayCols(My_Array));     } In this example, Columns = 20 will be printed. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > GetNumArrayRows -------------------------------------------------------------------------------- # GetNumArrayRows Name: GetNumArrayRows Syntax:     INTEGER GetNumArrayRows(STRING | INTEGER ARRAY_NAME); Description: Returns the number of rows for two-dimensional arrays or string arrays. Parameters: ARRAY_NAME is the array name as determined by the size. Return Value: For the data types in the table after this paragraph, the return value of GetNumArrayRows is shown. Example:     DIGITAL_INPUT TEST;     INTEGER My_Array[10][20];     PUSH TEST     {       PRINT("Rows = %d\n", GetNumArrayRows(My_Array));     } In this example, Rows = 10 will be printed. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > GetNumStructureArrayCols -------------------------------------------------------------------------------- # GetNumStructureArrayCols Name: GetNumStructureArrayCols Syntax:     INTEGER GetNumStructureArrayCols( STRUCTURE_ARRAY ); Description: Returns the number of columns in a structure array. Parameters: STRUCTURE_ARRAY is the structure array variable. Return Value: The number of columns in the structure array. Example:    STRUCTURE tagStruct    {       INTEGER i;    };    tagStruct myStructArr[10];    FUNCTION foo()    {       INTEGER numCols;       numCols = GetNumStructureArrayCols( myStructArr ); // numCols = 10        } Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later 3-Series: -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > Overview > Array Operations Overview -------------------------------------------------------------------------------- # Array Operations Overview Array Operations functions are used to perform generalized operations on arrays, such as getting bounds and setting the elements of an array to a known value in a given SIMPL+ program. | Operation | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | GetNumArrayCols | Finds the number of columns in a two-dimensional array or the size of the array for a one-dimensional array. | | GetNumArrayRows | Returns the number of rows for two-dimensional arrays or string arrays. Returns 0 for one dimensional arrays or strings. | | GetNumStructureArrayCols | Returns the number of columns in a structure array. | | ResizeArray | Changes the allocated size of the string array to NewNumElements of NewSize bytes or the integer array to NewNumElements rows of NewSize columns. | | ResizeStructureArray | Changes the allocated size of the structure array to NewSize elements. | | SetArray | Sets every element of ARRAY_NAME to the INIT_VALUE. | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > ResizeArray -------------------------------------------------------------------------------- # ResizeArray Name: ResizeArray Syntax:     SIGNED_INTEGER ResizeArray (ARRAY_NAME, INTEGER NewNumElements, INTEGER NewSize); Description: Changes the allocated size of the string array to NewNumElements of NewSize bytes or the integer array to NewNumElements rows of NewSize columns or the structure array to NewSize elements. NOTE: To use this function, the [#ENABLE_DYNAMIC] compiler directive must be present in the SIMPL+ module and the variable must be declared as [DYNAMIC]. NOTE: The NewNumElements parameter is optional. Parameters: ARRAYNAME can be either an integer or string array variable that needs a change in allocated size. NewNumElements indicates the new number of elements in the string array or number of rows for a 2-D integer array (should be 0 for 1-D arrays). NewSize indicates the new number of bytes in each string in the array or the new number of columns for the integer array. Return Value: | | | |----------|----------------------------------| | Status | Definition | | 0 | Success | | 0x8001 | Generic Error | | 0x8002 | Error – Max Resize limit reached | | 0x8004\* | Error – Element is not dynamic | | 0x8008 | Warning – Truncation will occur | | 0x8010 | Error – Out of memory | | 0x8020 | Error – Out of memory | | 0x8040 | Error – Out of memory | \* This error indicates that the #ENABLE_DYNAMIC compiler directive is missing from the SIMPL+ module and/or that the variable has not been declared as DYNAMIC. NOTE: The status might contain an error and a warning returned together. For example, if an array is resized from 20 to 10 elements, a truncation warning will result. However, if the system is out of memory, the resize cannot be completed. In this scenario, the returned status will be 0x8008 | 0x8010,  or 0x8018. Example: INTEGER MyIntArray[10][10]; STRING MyStringArray[10][10]; Function main() {     SIGNED_INTEGER  Status;     Status = ResizeArray(MyStringArray, 200, 80);     If (status != 0)                 Print(“Error occurred in resizing string array MyStringArray\n”)     Status = ResizeArray(MyIntArray, 200, 100);     If (status != 0)         Print(“Error occurred in resizing string array  MyIntArray\n”) } In this example, the columns and rows of MyIntArray and MyStringArray are changed from 10 and 10 (for both MyIntArray and MyStringArray) to 200 and 100 for MyIntArray and 200 and 80 for MyStringArray. Version: 2 Series only X Gen Not Supported [#ENABLE_DYNAMIC]: javascript:void(0); [DYNAMIC]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > ResizeStructureArray -------------------------------------------------------------------------------- # ResizeStructureArray Name: ResizeStructureArray Syntax:     SIGNED_INTEGER ResizeStructureArray (ARRAYNAME, INTEGER NewSize); Description: Changes the allocated size of the structure array to NewSize elements. NOTE: To use this function, the [#ENABLE_DYNAMIC] compiler directive must be present in the SIMPL+ module and the variable must be declared as [DYNAMIC]. Parameters: ARRAYNAME - a Structure array variable that needs a change in allocated size. NewSize indicates the new number of elements for the structure array. Return Value: | | | |----------|----------------------------------| | Status | Definition | | 0 | Success | | 0x8001 | Generic Error | | 0x8002 | Error – Max Resize limit reached | | 0x8004\* | Error – Element is not dynamic | | 0x8008 | Warning – Truncation will occur | | 0x8010 | Error – Out of memory | | 0x8020 | Error – Out of memory | | 0x8040 | Error – Out of memory | \* This error indicates that the #ENABLE_DYNAMIC compiler directive is missing from the SIMPL+ module and/or that the variable has not been declared as DYNAMIC. NOTE: The status might contain an error and a warning returned together. For example, if an array is resized from 20 to 10 elements, a truncation warning will result. However, if the system is out of memory, the resize cannot be completed. In this scenario, the returned status will be 0x8008 | 0x8010,  or 0x8018. Example: STRUCTURE tagMyStruct {     INTEGER MyIntArray[10][10];     STRING MyStrArray[10][10]; }; dynamic tagMyStruct myStructArr[10]; Function main() {           SIGNED_INTEGER  Status;           Status = ResizeStructureArray(myStructArr, 20);           If (status != 0)                    Print(“Error occurred in resizing array  MyStructArr\n”) } Version: 2 Series only X Gen not supported [#ENABLE_DYNAMIC]: javascript:void(0); [DYNAMIC]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Array Operations > SetArray -------------------------------------------------------------------------------- # SetArray Name: SetArray Syntax:  SetArray (ARRAY_NAME, INTEGER | STRING INIT_VALUE);  Description: Sets every element of ARRAY_NAME to the INIT_VALUE. Parameters: ARRAY_NAME is the name of the array to be initialized. It may be any array type. The INIT_VALUE may be a INTEGER or STRING. The following chart shows the various combinations of ARRAY_NAME types and INIT_VALUE types: NOTE:  When working with DIGITAL_OUTPUT arrays, if the INIT_VALUE evaluates to 0, the digital signals are set low. For any non-zero value, the outputs are set high. Return Value: None. Example:     DIGITAL_INPUT InitializeArrays;     INTEGER Levels[10];     STRING Names[5][5];     PUSH InitializeArrays     {       SetArray(Levels, 3);       SetArray(Levels, "3");       SetArray(Names, "xyz");       SetArray(Names, 0x41);     } The first line initializes all elements of the integer array Levels to contain the integer 3. The second line attempts to initialize the elements of the integer array Levels with a string value - an ATOI is done on the "3", which returns a 3, so that the end result is the same as the first line. The third line initializes all elements of the elements of the string array Names to contain the string value "xyz". The fourth line attempts to initialize the elements of the string array Names with an integer value - a CHR is done on the 0x41, which returns the string "A", so that the end result has all elements of the string array Names containing the string "A". Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > BIT > Bit -------------------------------------------------------------------------------- # Bit Name: Bit Syntax:     INTEGER Bit(STRING SOURCE, INTEGER SOURCE_BYTE, INTEGER                 BIT_IN_BYTE); Description: Determine the state of a specified bit in a particular byte of a given string. Parameters: SOURCE contains a STRING in which a bit of one byte is to be examined. Each character in SOURCE is considered one byte. SOURCE_BYTE references a character in the SOURCE string. The leftmost character in SOURCE is considered 1. BIT_IN_BYTE specifies which bit in the SOURCE_BYTE of SOURCE is to be examined. BIT_IN_BYTE starts at position 0 (least significant or rightmost bit of the byte). 7 is the most significant or leftmost bit of the byte. Return Value: Returns 0 or 1 for a valid bit position. Illegal bit references will return 65535. It is illegal if SOURCE_BYTE is 0 or greater than the length of the SOURCE string. Note that it is legal to specify a bit beyond 7. This will reference a bit in another byte. In this way, a source string can be used as a set of packed bit flags. The algorithm for determining which bit in which byte is set when BIT_IN_BYTE is greater than 7 is as follows. Actual Byte in SOURCE = (BIT_IN_BYTE / 8) + SOURCE_BYTE Actual Bit in Actual Byte = (BIT_IN_BYTE MOD 8) Applying this to BIT("abc",1,16) will reference bit 0 of byte 3 (the least significant bit of byte "c" in SOURCE). Example: This example takes an input string and creates an output string containing the elements of the input string that do not have the most significant bit (bit 7) set.     STRING_INPUT SOURCE$[100];     STRING_OUTPUT OUT$;     STRING TEMP$[100];     INTEGER I;     CHANGE SOURCE$     {       FOR(I = 1 to LEN(SOURCE$))       {         IF(BIT(SOURCE$, I, 7) = 0)         {           MAKESTRING(TEMP$, "%s%s", TEMP$, MID(SOURCE$, I, 1));         }         }       OUT$ = TEMP$;     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > BYTE > Byte -------------------------------------------------------------------------------- # Byte Name: Byte Syntax:     INTEGER Byte(STRING SOURCE, INTEGER SOURCE_BYTE); Description: Returns the integer equivalent of the byte at position SOURCE_BYTE within a SOURCE string. Parameters: SOURCE is a STRING of characters. Each character in SOURCE is considered one byte. SOURCE_BYTE references a character in the SOURCE string. The leftmost character in SOURCE is considered 1. Return Value: An integer containing the ASCII numeric value of the byte at position SOURCE_BYTE in the string SOURCE. If SOURCE_BYTE is greater than the length of the SOURCE string or is 0, 65535 is returned. Example: This piece of code will examine an input string to make sure that it starts with STX character (02). From there, it will test the second byte and process different command types accordingly.     STRING_INPUT IN$[100];     CHANGE IN$     {       IF(BYTE(IN$,1) = 02)       {         SWITCH(BYTE(IN$,2))         {           CASE (65):           {              // Process Command type 65 (A) here.              }           CASE (66):              {             // Process Command type 66 (B) here.           }         }       }     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > HIGH > High -------------------------------------------------------------------------------- # High Name: High Syntax:     INTEGER High(INTEGER VALUE); Description: Returns the upper most significant 8-bits of an Integer. Parameters: VALUE is an integer containing the value of the most significant  byte. It is not sign extended. Return Value: The upper 8-bits of the passed value. The return value is not signed extended, It is intended only for unsigned short integers (16 bits). Example:     ANALOG_INPUT VALUE;     CHANGE VALUE     {       PRINT("The upper byte of %X is %X\n", VALUE, HIGH(VALUE));     } This will print the input value and the upper 8-bits of the value in hexadecimal. For example, if VALUE is 0x1234, then the output is The upper byte of 1234 is 12. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > HighWord -------------------------------------------------------------------------------- # HighWord Name: HighWord Syntax:     INTEGER HighWord(LONG_INTEGER Value); Description: Returns the upper 16 significant bits of a LONG_INTEGER. Parameters: Value is a LONG_INTEGER containing the uppermost 16 significant bits the user wants. Return Value: The upper 16 significant bits of Value. Example: Function main() { LONG_INTEGER x; INTEGER y; x=0xAABBCCDD; y=HighWord(x); print("The UpperMost 16 Bits of %08IX are %04X\n", x, y);  } This will print: The UpperMost 16 bits of AABBCCDD are AABB. Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > LOW > Low -------------------------------------------------------------------------------- # Low Name: Low Syntax:     INTEGER Low(INTEGER VALUE) Description: Returns the lower least significant 8-bits of an Integer. Parameters: VALUE is an integer containing the value of the least significant byte. Return Value: The lower 8-bits of the passed value. Example:     ANALOG_INPUT VALUE;     CHANGE VALUE     {       PRINT("The lower byte of %X is %X\n", VALUE, LOW(VALUE));     } This will print the input value and the lower 8-bits of the value in hexadecimal. For example, if VALUE is 0x1234, then the output is The lower byte of 1234 is 34. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > LowWord -------------------------------------------------------------------------------- # LowWord Name: LowWord Syntax:     INTEGER LowWord(LONG_INTEGER Value); Description: Returns the lower 16 significant bits of a LONG_INTEGER. Parameters: Value is a LONG_INTEGER containing the lowermost 16 significant bits the user wants. Return Value: The lower 16 significant bits of Value. Example: Function main() { LONG_INTEGER x; INTEGER y; x=0xAABBCCDD; y=LowWord(x); print("The LowerMost 16 Bits of %08IX are %04X\n", x, y);  } This will print: The UpperMost 16 bits of AABBCCDD are CCDD. Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > LowerChar -------------------------------------------------------------------------------- # LowerChar Name: LowerChar Syntax:     INTEGER LowerChar(INTEGER character); Description: Converts the given character to lower case, so long as the character is between 'A' (0x41) and 'Z' (0x5A). Parameters: Value is an INTEGER character: The character to convert to lower case. Return Value: The character converted to lower case.  If the character is not an upper case character, the same character is returned.   Example: INTEGER Converted1, Converted2; Converted1 = LowerChar('a'); Converted2 = LowerChar('5'); Print("Converted1=%c, Converted2=%c\n", Converted1, Converted2); Converted1=a (this is returned if the converted character was an upper case character). Converted2=5 (this would be returned if the character to be converted was not an upper case character). Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > Overview > Bit & Byte Functions Overview -------------------------------------------------------------------------------- # Bit & Byte Functions Overview These functions perform bit and byte masking operations in a given SIMPL+ program. | | | |----|----| | Function | Description | | [Bit] | Determines the state of a specified bit in a particular byte of a given string. | | [Byte] | Returns the integer equivalent of the byte at position SOURCE_BYTE within a SOURCE string. | | [High] | Returns the upper most significant 8-bits of an Integer. | | [HighWord] | Returns the upper 16 significant bits of a LONG_INTEGER. | | [Low] | Returns the lower least significant 8-bits of an Integer. | | [LowWord] | Returns the lower 16 significant bits of a LONG_INTEGER. | | [LowerChar] | Converts the given character to lower case, so long as the character is between 'A' (0x41) and 'Z' (0x5A). | | [UpperChar] | Converts the given character to upper case, so long as the character is between 'a' (0x61) and 'z' (0x7A). | | [SetByte] | Sets the byte at the position given by POSITION in the string given by SOURCE to the value in VALUE. | [Bit]: BIT.md [Byte]: BYTE.md [High]: HIGH.md [HighWord]: HighWord.md [Low]: LOW.md [LowWord]: LowWord.md [LowerChar]: LowerChar.md [UpperChar]: UpperChar.md [SetByte]: SetByte.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > RotateLeft -------------------------------------------------------------------------------- # RotateLeft Name: RotateLeft Syntax:  INTEGER RotateLeft( INTEGER X, INTEGER Y ); Description: Rotate X to the left (more significant direction) by Y bits; full 16 bits used. Same as {{ operator. (refer to [RotateRight] explanation) Parameters: X is the INTEGER to have bits rotated Y is the amount of bits to rotate Return Value: An INTEGER containing the result of the rotated bits. Example: INTEGER X, Y, result; result = RotateLeft( X, Y );   Version: X Generation:  Not Supported 2-Series:  SIMPL v2.03.18 and later [RotateRight]: RotateRight.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > RotateLeftLong -------------------------------------------------------------------------------- # RotateLeftLong Name: RotateLeftLong Syntax:     LONG_INTEGER RotateLeftLong( LONG_INTEGER X, INTEGER Y ); Description: Rotate X to the left by Y bits; full 32 bits used. Parameters: X is the LONG_INTEGER to have bits rotated Y is the amount of bits to rotate Return Value: A LONG_INTEGER containing the result of the rotated bits. Example: LONG_INTEGER X, Y, result; result = RotateleftLong( X, Y );   Version: X Generation:  Not Supported 2-Series:  SIMPL v2.03.18 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > RotateRight -------------------------------------------------------------------------------- # RotateRight Name: RotateRight Syntax:     INTEGER RotateRight( INTEGER X, INTEGER Y ); Description: Rotate X to the right by Y bits; full 16 bits used. Same as }} operator. e.g., Each bit takes the value of the bit that is Y bits more significant than it is. The most significant bit(s) are set from the least significant bits. Parameters: X is the INTEGER to have bits rotated Y is the amount of bits to rotate Return Value: An INTEGER containing the result of the rotated bits. Example: INTEGER X, Y, result; result = RotateRight( X, Y );   If X = 0x1234 and Y is 1, then the result is 0x091A Version: X Generation:  Not Supported 2-Series:  SIMPL v2.03.18 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > RotateRightLong -------------------------------------------------------------------------------- # RotateRightLong Name: RotateRightLong Syntax:     LONG_INTEGER RotateRightLong( LONG_INTEGER X, INTEGER Y ); Description: Rotate X to the right by Y bits; full 32 bits used. Parameters: X is the LONG_INTEGER to have bits rotated Y is the amount of bits to rotate Return Value: A LONG_INTEGER containing the result of the rotated bits. Example: LONG_INTEGER X, Y, result; result = RotateRightLong( X, Y );   Version: X Generation:  Not Supported 2-Series:  SIMPL v2.03.18 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > SetByte -------------------------------------------------------------------------------- # SetByte Name: SetByte Syntax:     INTEGER SetByte(STRING SOURCE, INTEGER POSITION, INTEGER VALUE); Description: Sets the byte at the position given by POSITION in the string given by SOURCE to the value in VALUE. Parameters: SOURCE is a STRING of characters. Each character in SOURCE is considered one byte. POSITION references a character in the SOURCE string. The leftmost character in SOURCE is considered 1.  The only valid positions are 1 to LEN(SOURCE).  Any other position is out of bounds and will return an error. VALUE is the data to set the source string position to.  If it is greater than 255, the lower 8 bits are used. Return Value: 0 if success, -1 if failure. Example: function main() {    STRING Text$[25];    INTEGER ReturnValue;    Text$="CPQ1704TKS";    ReturnValue = SetByte(Text$, 3, 'E');    if(ReturnValue \<\> 0)    {       print("Error, could not Set Byte at given position\n");    }    else    {       print("New String is: \<%s\>\n", Text$);    } } In this example, the output is "New String is: \" Version: 2-Series Only:  SIMPL v2.10.10 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Bit & Byte Functions > UpperChar -------------------------------------------------------------------------------- # UpperChar Name: UpperChar Syntax:     INTEGER UpperChar(INTEGER character); Description: Converts the given character to upper case, so long as the character is between 'a' (0x61) and 'z' (0x7A). Parameters: Value is an INTEGER character: The character to convert to upper case. Return Value: The character converted to upper case.  If the character is not a lower case character, the same character is returned.   Example: INTEGER Converted1, Converted2; Converted1 = UpperChar('a'); Converted2 = UpperChar('5'); Print("Converted1=%c, Converted2=%c\n", Converted1, Converted2); Converted1=A (this is returned if the converted character was a lower case character). Converted2=5 (this would be returned if the character to be converted was not a lower case character). Version: SIMPL+ Version 2.10.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Branching & Decision Constructs > BREAK -------------------------------------------------------------------------------- # BREAK Name: BREAK Syntax:     BREAK; Description: Terminates the innermost DO-UNTIL, FOR, or WHILE loop before the exit condition is met. Execution resumes after the end of the loop. Example:     INTEGER X;     ANALOG_INPUT Y;     X=0;     WHILE(X\<25)     {       IF(Y = 69)         BREAK;       X = X + 1;       PRINT("X=%d\n", X);     } In this example, the WHILE loop will terminate if the ANALOG_INPUT Y equals the value of 69. Otherwise, the loop will exit via the normal termination condition. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Branching & Decision Constructs > CONTINUE -------------------------------------------------------------------------------- # CONTINUE Name: CONTINUE Syntax:     CONTINUE; Description: Resumes execution at the top of the innermost DO-UNTIL, FOR, or WHILE loop before the exit condition is met. Execution resumes at the start of the loop. Example:     INTEGER X;     ANALOG_INPUT Y;     X=0;     WHILE(X\<25)     {         IF(Y = 69)         {            CONTINUE;         }       PRINT( “X=%d”, X );           X = X + 1;     } In this example, the WHILE loop will  print the value of X if ANALOG_INPUT Y does not equal the value of 69.  When Y=69, the loop will continue executing from the top of the loop.  If Y does not equal 69, the loop will exit via the normal termination condition. Version: 2-Series:  SIMPL v2.01.05 and later 3-Series:  SIMPL v4.02.17 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Branching & Decision Constructs > CSWITCH -------------------------------------------------------------------------------- # CSWITCH Name: CSWITCH Syntax: CSWITCH (\) {   CASE (\):   [{]         \         [break;]   [}]   CASE (\):   [{]        \        [break;]   [}]   [DEFAULT:   [{]        \        [break;]   [}] } NOTE: In SIMPL+ v3.01.00 and later, the 'break' statement is required to terminate the case statement block that it resides within.  If no 'break' statement exists, the program will continuing executing to the next case statement block or default statement block. NOTE:  Many CASE statements may be used in the body of the CSWITCH.   Description: CSWITCH is a more direct method of writing a complex IF-ELSE-IF statement. In the CSWITCH, if \ is equal to a CASE’s constant, then the statement block for that CASE value is executed. This same method would apply to as many CASE statements as are listed in the body of the CSWITCH. Note that if any of the \ blocks are only a single statement, the { and } characters on the CASE may be omitted. If no condition is met in the CASE statements, the DEFAULT case, if specified, is used. CSWITCH has the restriction that the case statement only contains unique integer constants. CSWITCH differs from SWITCH in that the operating system is able to evaluate and execute the CSWITCH statement faster.  Therefore, you should use CSWITCH in place of SWITCH whenever unique constants are being evaluated. Example: ANALOG_INPUT AIN; INTEGER X; CSWITCH( AIN ) {      CASE (2):      {           X = 0;           break; // terminate this case statement block      }      CASE (3):      {           X = AIN;           // continue executing to next case statement block ==\> case(5)      }      CASE (5):      {           X = X + AIN + 1;           break;      }      DEFAULT:      {           PRINT("Unknown command %d!\n", AIN);           break;      }      } In this example, if the value of AIN is 2, X is set equal to 0. If AIN is 3, X is set AIN + AIN + 1. If AIN is 5, X is set equal to AIN+1. If AIN is any other value, an error message is printed. Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Branching & Decision Constructs > IF - ELSE -------------------------------------------------------------------------------- # IF - ELSE Name: IF - ELSE Syntax:     IF ( \)     [{]       \     [}]     [ELSE]     [{]       \     [}]] Since \ can be an IF construct, you can string out a series of IF-ELSE-IF statements of the form:     IF (\)     [{]       \     [}]     [ELSE] IF (\)     [{]       \     [}]] NOTE:  A final ELSE may be used to express default handling if none of the previous conditions were met.     IF (\)     [{]       \     [}]     [ELSE] IF (\)     [{]       \     [}]     [ELSE]     [{]       \     [}] Description: Executes a piece of code only if its associated \ evaluates to true. Many expressions can be tested if the IF-ELSE-IF construct is used. Note that only one \ block in an IF-ELSE or IF-ELSE-IF construct is executed. In any section of the construct, if \ is only a single statement, then the { and } characters may be omitted. Example:     STRING_INPUT IN$[100];     STRING Y$[100];     INTEGER X;     IF (IN$ = "STRING1")     {       X=5;       Y$ = IN$;     }     ELSE     {       X=6;       Y$ = "";     } In this example, if IN$ is equal to STRING1, then the first two statements are executed. If IN$ is a different value, then the second groups of statements are evaluated. A more complex IF-ELSE-IF construct appears as:     IF (IN$ = "STRING1")     {       X=5;       Y$ = IN$;     }     ELSE IF (IN$="STRING2")     {       X=6;       Y$ = "";     }     ELSE     {       X = 7;       Y$ = "ZZZ";     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Branching & Decision Constructs > SWITCH -------------------------------------------------------------------------------- # SWITCH Name: SWITCH Syntax:     SWITCH (\)     {       CASE (\):      [{]         \      [}]       CASE (\):      [{]         \      [}]      [DEFAULT:      [{]         \      [}]     } NOTE:  Many CASE statements may be used in the body of the SWITCH. Description: SWITCH is a more direct method of writing a complex IF-ELSE-IF statement. In the SWITCH, if \ is equal to \, \ is executed. If \ is equal to \, \ is executed. This same method would apply to as many CASE statements as are listed in the body of the SWITCH. Note that if any of the \ blocks are only a single statement, the { and } characters on the CASE may be omitted. SWITCH has the restriction that the expressions may not be STRING expressions, they can only be INTEGER type expressions. SWITCH may only have up to 32 CASE statements in SIMPL+ Version 1.00. If more are used, a "FULL STACK" error results at the time of uploading the module to the control system. Version 2.00 has no restriction. When a SWITCH is evaluated, the first matching CASE is used. If another CASE (or more) would have matched, only the first one is used. If no condition is met in the CASE statements, the DEFAULT case is used if specified. Example:     ANALOG_INPUT AIN;     INTEGER X;     SWITCH(AIN)     {       CASE (2):       {         X = 0;       }       CASE (3):       {         X = AIN;       }       CASE (5):       {         X = AIN + 1;       }       DEFAULT:         PRINT("Unknown command %d!\n", AIN);     } In this example, if the value of AIN is 2, X is set equal to 0. If AIN is 3, X is set equal to AIN. If AIN is 5, X is set equal to AIN+1. If AIN is any other value, an error message is printed. Version: X Generation SIMPL v1.20.01, 32 CASE statements maximum. SIMPL v1.50.06 and later, no CASE restriction. 2-Series SIMPL v2.01.05 and later [same features as X Generation SIMPL v1.50.06] -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > Overview > CEN-OEM Specific Definitions Overview -------------------------------------------------------------------------------- # CEN-OEM Specific Definitions Overview The CEN-OEM has one serial port which is used to communicate with a destination device. SIMPL+ defines several special purpose variables exclusively to work with the CEN-OEM to manipulate this serial port. These variables are only valid when the file is saved with an OEM extension. Each OEM variable has a specific type (DIGITAL_INPUT, etc.) to which all the same rules as any other variable declared of that type have. In the following examples, the "device" port is the port that talks to the equipment (device) being controlled. The "main" port is the computer port of the CEN-OEM. This port is usually used for communicating with a host computer for maintenance, but various pins may be used for other applications as follows. [_OEM_BREAK] [_OEM_CD] [_OEM_CTS][][\ _OEM_DTR] [_OEM_LONG_BREAK] [_OEM_MAX_STRING] [_OEM_PACING] [_OEM_RTS] [_OEM_STR_IN] [_OEM_STR_OUT] [_OEM_BREAK]: _OEM_BREAK.md [_OEM_CD]: _OEM_CD.md [_OEM_CTS]: _OEM_CTS.md [\ _OEM_DTR]: _OEM_DTR.md [_OEM_LONG_BREAK]: _OEM_LONG_BREAK.md [_OEM_MAX_STRING]: _OEM_MAX_STRING.md [_OEM_PACING]: _OEM_PACING.md [_OEM_RTS]: _OEM_RTS.md [_OEM_STR_IN]: _OEM_STR_IN.md [_OEM_STR_OUT]: _OEM_STR_OUT.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM BREAK > _OEM_BREAK -------------------------------------------------------------------------------- # _OEM_BREAK Name: _OEM_BREAK Syntax:     _OEM_BREAK = \;  // Write to Variable or Any expression that can use a variable as part of its contents. Description: When set to a non-zero value, causes a short break to be transmitted on the port. A Short break is 17-20 bits of logic low. When the system is done generating the short break, it will set the variable to 0. The variable may also be read back from to determine its current status. It is treated the same as a DIGITAL_OUTPUT. Example:     _OEM_BREAK = 1; // Generate A Short Break Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM CD > _OEM_CD -------------------------------------------------------------------------------- # _OEM_CD Name: _OEM_CD Syntax: Any expression that can use a variable as part of its contents. Description: This variable is treated as a DIGITAL_INPUT and may be read from only. CD is the acronym for Carrier Detect. When a modem is hooked up to an RS-232 port and a connection (carrier) is made, the modem typically drives this pin high to let the connected hardware know that a data connection is present. This line may be used for other purposes depending on the hardware connected to the CEN-OEM. Example:     PUSH _OEM_CD     {       PRINT("Carrier Detect Pin has gone high!\n");     } Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM CTS > _OEM_CTS -------------------------------------------------------------------------------- # _OEM_CTS Name: _OEM_CTS Syntax: Any expression that can use a variable as part of its contents. Description: This variable is treated as a DIGITAL_INPUT and may be read from only. CTS is the acronym for Clear To Send. In flow control for handshaking, a device will typically control this line, and raise it high when the CEN-OEM is allowed to transmit, and drop it low when it wants the CEN-OEM to stop transmitting. It can also be used in other situations besides flow control, and in these situations, the CEN-OEM can monitor the status of the line directly through this pin. Example:     PUSH _OEM_CTS     {       PRINT("CTS Pin has gone high!\n");     } Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM DTR > _OEM_DTR -------------------------------------------------------------------------------- # _OEM_DTR Name: _OEM_DTR Syntax:     _OEM_DTR = \; or Any expression that can use a variable as part of its contents. Description: When set to a non-zero value,  raises the DTR pin high. This pin is typically used to signify "Data Terminal Ready", which means that the CEN-OEM is telling an external piece of equipment that it is online and ready to function. The pin may be used for other purposes (or not at all). This value is treated as a DIGITAL_OUTPUT and may be read. Example:     PUSH _OEM_CTS     {       PULSE(500, _OEM_DTR);     } The above example will pulse the DTR pin for 5-seconds when the CTS line goes high. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM LONG BREAK > _OEM_LONG_BREAK -------------------------------------------------------------------------------- # _OEM_LONG_BREAK Name: _OEM_LONG_BREAK Syntax:     _OEM_LONG_BREAK = \; or Any expression that can use a variable as part of its contents. Description: When set to a non-zero value, causes the start of a break being transmitted on the port. A break is continuous logic low being generated on the port. In order to stop break generation, the variable should be set to 0. The variable may also be read back from to determine its current status. It is treated the same as a DIGITAL_OUTPUT. If break generation is in progress and data transmission on _OEM_STR_OUT will be ignored. Example:     PUSH _OEM_CTS     {       _OEM_LONG_BREAK = 1;       WAIT(100)         _OEM_LONG_BREAK=0;     } In this example, the break is generated for 1-second when the CTS pin is driven high. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM MAX STRING > _OEM_MAX_STRING -------------------------------------------------------------------------------- # _OEM_MAX_STRING Name: _OEM_MAX_STRING Syntax:     _OEM_MAX_STRING = \; or Any expression that can use a variable as part of its contents. Description: Controls the maximum embedded packet size that is transmitted on the Ethernet port. This variable is treated the same as ANALOG_OUTPUT. The default is 250 bytes but it is recommended that this value not be changed for most applications. Example:     _OEM_MAX_STRING = 1000;   In this example, the maximum embedded packet size is changed to 1000 bytes. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM PACING > _OEM_PACING -------------------------------------------------------------------------------- # _OEM_PACING Name: _OEM_PACING Syntax:     _OEM_PACING = \; or Any expression that can use a variable as part of its contents. Description: Controls the number of milliseconds the system will delay between sending bytes in a given string. This variable is treated the same as ANALOG_OUTPUT. The maximum value allowed is 255 (250ms). Values greater than 255 will use the lower byte of the number. Example:     CHANGE _OEM_STR_IN     {       IF(_OEM_STR_IN = "\x01\x02")       {         _OEM_STR_OUT = "\x02ACK\x03";         CLEARSTRING(_OEM_STR_IN);       }     }     FUNCTION MAIN()     {       _OEM_PACING = 10;     } In this example, the pacing is set to 10ms. When the string "\x01\x02" comes into the port, a 5-byte string is sent out the port. The system waits 10ms after generating each character before sending the next one. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM RTS > _OEM_RTS -------------------------------------------------------------------------------- # _OEM_RTS Name: _OEM_RTS Syntax:     _OEM_RTS = \; or Any expression that can use a variable as part of its contents. Description: This variable is treated the same as DIGITAL_OUTPUT. In a program where hardware handshaking is not being used, the program may control the RTS pin for its own application. Writing a non-zero value to this variable sets the RTS pin high, writing 0 sets it low. Example:     PUSH _OEM_CTS     {       DELAY(10);       _OEM_RTS = 1;     } In this program, the RTS pin will be driven high by the CEN-OEM 0.1-seconds after the CTS pin is driven high by an external system. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM STR IN > _OEM_STR_IN -------------------------------------------------------------------------------- # _OEM_STR_IN Name: _OEM_STR_IN Syntax: Any expression where a BUFFER_INPUT is legal. Description: This variable is treated the same as BUFFER_INPUT and reflects data coming into the CEN-OEM input buffer. The buffer is 255 bytes wide. Example:     INTEGER I;     CHANGE _OEM_STR_IN     {       FOR(I=1 to len(_OEM_STR_IN))         IF(byte(_OEM_STR_IN, I) = 0x7F           _OEM_STR_OUT = "\x15";       CLEARSTRING(_OEM_STR_IN);     } In this example, whenever the input buffer changes, it is scanned for the character with the hex value of 0x7F. Each time it is present, a 0x15 is transmitted. The buffer is cleared at the end of the iteration. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > CEN-OEM Specific Definitions > OEM STR OUT > _OEM_STR_OUT -------------------------------------------------------------------------------- # _OEM_STR_OUT Name: _OEM_STR_OUT Syntax: Any expression where a BUFFER_OUTPUT is legal. Description: This variable is treated the same as BUFFER_OUTPUT and reflects data coming from the CEN-OEM input buffer. The buffer is 255 bytes wide. Example:     INTEGER I;     CHANGE _OEM_STR_OUT     {       FOR(I=1 to len(_OEM_STR_OUT))         IF(byte(_OEM_STR_OUT, I) = 0x7F           _OEM_STR_IN = "\x15";       CLEARSTRING(_OEM_STR_OUT);     } In this example, whenever the input buffer changes, it is scanned for the character with the hex value of 0x7F. Each time it is present, a 0x15 is transmitted. The buffer is cleared at the end of the iteration. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Class Objects > CEvent -------------------------------------------------------------------------------- # CEvent **Name:** CEvent **Syntax:**      CEvent event; **Description:** Event is a synchronization primitive which allows threads to communicate with each other by signaling. The CEvent is signaled on startup. A thread waits on the event by calling “Wait” with the specified timeout ( -1 for infinite). The timeout is specified in milliseconds and is the time that the thread will wait before returning. Please use the return value to ensure that the thread has access to the event before continuing. Once the CEvent has been signaled, it will wake up the first thread which is blocked on this event. Once that thread has been awakened, the event is reset and subsequent calls on the “Wait” will block and return an error (if a finite timeout is specified) until the event gets signaled again. The event is signaled using the “Set” call. **Class Members:** class CEvent { FUNCTION Close(); SIGNED_LONG_INTEGER Reset(); SIGNED_LONG_INTEGER Set(); SIGNED_LONG_INTEGER Wait( SIGNED_LONG_INTEGER timeOutInMs ); } **Class Member Description:** **Close** This function should be invoked when the program is done using the event. This will free out all the associated resources. **Set** The set function sets the state of the event to be signaled and will wake up a single thread. If there are no waiting threads, the event remains signaled until a thread attempts to wait on it, or until its Reset method is called. Calling a Set on an event which is already set does not do anything. The function returns a 1 if successful or 0 if failed. **Reset** The Reset function is used to set the state of the event to be non-signaled. The function returns a 1 if successful or 0 if failed. **Example:** DIGITAL_INPUTtest1,test2; CEvent myEvent; Function ShowEventUsage() {  INTEGER retVal;       // Wait on the event to happen.  // By default the event is signaled so the first time we come into this function the event will be signaled and we  // will fall through. Subsequent calls will block until the event is signaled using the Set method       // The wait takes a timeout parameter in milliseconds. Pass a -1 for an INFINITE WAIT and a 0 for no timeout  do  {  print(" Waiting for event to get signaled \r\n");  retVal = myEvent.Wait(-1);  if (retVal = 1)  print(" Event signaled \r\n");  else   print(" Event wait failed - Event not signaled \r\n");  } until (0); } PUSH test1 {  INTEGER retVal;  retVal = myEvent.Set();  print(" Signaling event Now. Returned %ld \r\n", retVal); } RELEASE test1 { } PUSH test2 { } RELEASE test2 { } Function Main() { WaitForInitializationComplete();       // Invoke the function - event will be triggered once since it is set on startup  ShowEventUsage(); } **Version:** X Generation: N/A 2-Series: N/A 3-Series: SIMPL v4.02.02+ -------------------------------------------------------------------------------- ## Language Constructs & Functions > Class Objects > CMutex > CMutex -------------------------------------------------------------------------------- # CMutex **Name:** CMutex **Syntax:**      CMutex mutex; **Description:** Mutex is a synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex. A mutex object is a synchronization object whose state is set to signaled when it is not owned by any thread and non-signaled when it is owned. Only one thread at a time can own a mutex object. A mutex is available on startup and can be grabbed using the WaitForMutex  call. The thread that owns a mutex can request the same mutex in repeated calls to WaitForMutex  without blocking its execution. However, the thread must call the ReleaseMutex method the same number of times to release ownership of the mutex. **Class Members:** class CMutex { FUNCTION Close(); FUNCTION ReleaseMutex(); SIGNED_LONG_INTEGER WaitForMutex(); } **Class Member Description:** **Close** This function should be invoked when the program is done using the mutex. This will free all the associated resources. **ReleaseMutex** This function is invoked to release the mutex. If the calling thread does not own the mutex then an exception is thrown. **WaitForMutex** This function is used to get access to the mutex. This is a blocking call and the thread will block until it can get access to the mutex. Once a thread has access to the mutex, it can call the WaitForMutex function repeatedly without blocking. However, the thread must call the ReleaseMutex method the same number of times to release ownership of the mutex. While one thread has access to the mutex, another thread will block infinitely until it gets access to the mutex. **Example:** DIGITAL_INPUTtest1,test2; CMutex myMutex; CEvent myEvent; PUSH test1 {  INTEGER retVal;  // By default the mutex is not owned by the callee - Use WaitForMutex to grab the mutex. There is no timeout for the WaitForMutex function  // Use ReleaseMutex to release the mutex       // Mutex is used to provide mutual exclusion across two functions. If one thread has the mutex another one cannot  // We need to release the mutex from within the same thread which obtained the mutex  print(" Inside callback for test1 - Try grabbing the mutex \r\n");  myMutex.WaitForMutex(); print(" Inside callback for test1 - Obtained mutex. Now waiting now event which will tell us to release the mutex \r\n");       // Wait for an event to be signaled, then we can then release the mutex  myEvent.Wait(-1);  print(" Releasing the mutex now \r\n");  myMutex.ReleaseMutex(); } RELEASEtest1 {  print(" Setting the event now which will tell the thread to release the mutex \r\n");  myEvent.Set(); } PUSHtest2 {  print(" Inside callback for test2 - Try grabbing the mutex \r\n");  myMutex.WaitForMutex();  print(" Inside callback for test2 - Obtained mutex Now waiting now event which will tell us to release the mutex \r\n");       // Wait for an event to be signaled, then we can then release the mutex  myEvent.Wait(-1);  print(" Releasing the mutex now in callback 2\r\n");  myMutex.ReleaseMutex(); } RELEASEtest2 {  try  {   print(" Inside release callback for test2 - Release the mutex \r\n");  // Release mutex throws an exception if we are trying to release a mutex which we do not own  // This will throw an exception  myMutex.ReleaseMutex();  print(" Inside release callback for test2 - Released the mutex \r\n");  }  catch  {             // This is expected since the thread which owns the mutex has to release it  print(" Exception thrown %s \r\n", GetExceptionMessage());  // Now set the event so that we can release the mutex  myEvent.Set();  } } FunctionMain() { WaitForInitializationComplete();       // Invoke the function - event will be triggered once since it is set on startup myEvent.Reset(); } **Version:** X Generation: N/A 2-Series: N/A 3-Series: SIMPL v4.02.02+ -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Array out of bounds -------------------------------------------------------------------------------- # Array out of bounds An attempt was made to access an element of an array that is outside the declared range of the array. For an array size declaration, the allowable indices are 0 through the declared size. For example, INTEGER X[10][10] would allow access to X[0][0] through X[10][10]. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Bad printf format -------------------------------------------------------------------------------- # Bad printf format The MAKESTRING or PRINT functions have encountered an invalid character following the % character. The most common reason for this is when a % is actually required, %% should be used to print a single % character. Refer to MAKESTRING and PRINT for a full list of valid format specifiers. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Full Stack -------------------------------------------------------------------------------- # Full Stack The SWITCH construct may only have 32 CASE statements in SIMPL+ Version 1.00. If more than 32 are used, this error appears. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Library not found -------------------------------------------------------------------------------- # Library not found This occurs when a module tries to call a user-defined function that exists in an external library which was specified with #CRESTRON_LIBRARY or #USER_LIBRARY. During compilation, the compiler builds a file containing the libraries to send to the control system. Typically, this could be caused by a transfer error which would be seen at load time. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Rstack overflow -------------------------------------------------------------------------------- # Rstack overflow The Rstack that this message refers to is the Return Stack. When an event is interrupted by some means (via a process_logic statement or an implied task switch from inside a loop), information about that event is put on the Return stack, so that when the event resumes, it knows how to continue. When the event continues, the saved information is removed from the return stack. If during this interruption the event is called again, and interrupted again, more information is saved on the return stack. The return stack is of limited size and if this keeps occurring, the Return stack will not have enough space to contain more data and this message will be issued. For a further discussion of how to handle the programming when events are likely to be interrupted, refer to "[Task Switching]". [Task Switching]: ../../Task_Switching/Task_Switching_for_2-Series_Control_Systems.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Runtime Overview > Common Runtime Errors Overview -------------------------------------------------------------------------------- # Common Runtime Errors Overview The following errors will occur at runtime. In order for these error messages to be seen, the Crestron Viewport must be open and communications with the control system (via Ethernet or the computer port) must be established. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Scheduler is full -------------------------------------------------------------------------------- # Scheduler is full Any time-based function such as DELAY, PULSE, or WAIT will schedule an event in SIMPL+. A scheduled event will add one or more entries to the SIMPL+ scheduler. The scheduler currently supports 200 events and is global to the entire SIMPL+ system. If the scheduler is full and another event is added, this message is issued. NOTE:  The message "Skedder Full" is issued from a SIMPL program, not SIMPL+. "Skedder full" is a similar problem, but results if too many time-based events are occurring in a SIMPL program. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > String array out of bounds -------------------------------------------------------------------------------- # String array out of bounds An attempt was made to access an element of a string array that is outside the declared range of the array. Remember that for an array size declaration, the allowable indices are 0 through the declared size. For example, STRING X$[5][20] declares six strings of 20 bytes each, accessed via X$[0] through X$[5]. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Common Runtime Errors > Too much ram allocated > Too Much RAM Allocated -------------------------------------------------------------------------------- # Too Much RAM Allocated Too much RAM was allocated for the data structures. Approximately 60K is available for user data. When compiling a program, it will tell you how much memory is required for one instance of the module. Each instantiation of the module in a SIMPL program takes up that much more space. For example, if a module says it requires 100 bytes after it is compiled, two instances of that module will require 200 bytes. If this message is received, reduce the number of variables. If string or buffers have been declared overly large, this is an easy place to reduce memory requirements. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > Overview > Compiler Directives Overview -------------------------------------------------------------------------------- # Compiler Directives Overview Compiler directives are used by the SIMPL+ compiler to control attributes of the symbol without generating actual SIMPL+ code. They come at the beginning of the program, and are used to provide explicit instructions to the compiler. As such, directives are not part of the SIMPL+ language itself and are distinguished from actual SIMPL+ code by the pound sign (#) preceding their names. Compiler directives are provided in the template file that is created when a new program is started. The compiler directives are as follows: | Directive | Description | | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | #ANALOG_SERIAL_EXPAND | This provides a way to expand, or add, inputs and/or outputs for a specified symbol. | | #BEGIN_PARAMETER_PROPERTIES, #END_PARAMETER_PROPERTIES | This directive is used to declare parameter properties. | | #CATEGORY | A Category is the name of the folder in the Logic Symbols library tree where the module is shown. | | #CRESTRON_LIBRARY | Directs the compiler to include code from a Crestron provided library. | | #CRESTRON_SIMPLSHARP_LIBRARY | Directs the compiler to include code from a Crestron SIMPL# library. The module name specified is the library filename without the CLZ extension. | | #DEFAULT_NONVOLATILE | Program variables retain their value if hardware power is lost. | | #DEFAULT_VOLATILE | Program variables will not retain their value if hardware power is lost. | | #DEFINE_CONSTANT | Define a that will be substituted anywhere in the current source file where is used. | | #DIGITAL_EXPAND | This provides a way to expand, or add, inputs and/or outputs for a specified symbol. | | #ENABLE_STACK_CHECKING | Allows run-time stack checking to be performed on a given module. If there is a stack overflow, an error will be produced. | | #ENABLE_TRACE | When invoked, this enables trace output. If it is not invoked no console output will be generated. | | #ENCODING_ASCII | This directive ensures that any strings in the SIMPL+ module without explicit encoding keywords are marked with ASCII encoding. | | #ENCODING_UTF16 | This directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with UTF16 encoding. | | #ENCODING_INHERIT_FROM_PARENT | This directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with default encoding of the parent of this module. | | #ENCODING_INHERIT_FROM_PROGRAM | This directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with default encoding of the SIMPL program. | | #HELP | Several #HELP lines can be specified. | | #HELP_BEGIN … #HELP_END | The #HELP_BEGIN, #HELP_END pair makes it easier to create help since each line does not need a separate #HELP directive. | | #HINT | The #HINT shows up in the status bar and provides a short tactical clue as to the function of the symbol in the same way that Crestron-defined built-in symbols do. | | #IF_DEFINED … #ENDIF | Results in compilation of the only if has not been previously defined. | | #IF_NOT_DEFINED … #ENDIF | Results in compilation of the only if has not been previously defined. | | #IF_SERIES2 | Using this compiler directive will cause the compiler to only include the statements for the 2-series control system. | | #IF_SERIES3 | Using this compiler directive will cause the compiler to only include the statements for the 3-series control system. | | #IF_SERIES4 | Using this compiler directive will cause the compiler to only include the statements for the 4-series control system. | | #INCLUDEPATH | Directs the compiler to search for User SIMPL+ and SIMPL# Libraries in the specified paths. | | #LARGE_STACK | This is used to increase the stack size when necessary. | | #MAX_INTERNAL_BUFFER_SIZE | Sets the maximum size for the compiler’s internal string allocations. | | #OUTPUT_SHIFT | This provides a way to arrange the inputs and outputs on the symbol graphic so that they line up and are easy to read. | | #PRINT_TO_TRACE | When invoked, this enables converts all print statements to trace statements. | | #SYMBOL_NAME | By specifying , this name will show up on the header of the symbol in the detail view as well as in the USER SIMPL+ section of the Symbol Library. | | #USER_LIBRARY | Directs the compiler to include code from a User written library. | | #USER_SIMPLSHARP_LIBRARY | Directs the compiler to include code from a User SIMPL# library. The module name specified is the library filename without the CLZ extension. Relative or absolute path are not allowed within this directive (see #INCLUDEPATH). | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > PARAMETER PROPERTIES > PARAMETER_PROPERTIES -------------------------------------------------------------------------------- # PARAMETER_PROPERTIES Parameters in SIMPL+, have certain attributes by default (see [INTEGER_PARAMETER],  [LONG_INTEGER_PARAMETER], [SIGNED_INTEGER_PARAMETER], [SIGNED_LONG_INTEGER_PARAMETER], [STRING_PARAMETER] for more information)   Parameters may be further restricted by declaring parameter Properties.  The general format is below. NOTE:  Note all combinations below can or should be used at the same time. Syntax: #BEGIN_PARAMETER_PROPERTIES parameter_variable[, parameter_variable ...]    propValidUnits= unitString or unitDecimal|unitHex|unitPercent|unitCharacter|unitTime|unitTicks;    propDefaultUnit=unitString or unitDecimal or unitHex or unitPercent or unitCharacter or unitTime or unitTicks;    propDefaultValue=default_value or "default_value";    propList={ "value","label" },{ "value","label" };    propBounds=lower_bound , upper_bound;    propShortDescription= "status_bar_hint_text"; #BEGIN_PROP_FULL_DESCRIPTION line_1 ... line_n   #END_PROP_FULL_DESCRIPTION #BEGIN_PROP_NOTES line_1 ... line_n #END_PROP_NOTES #END_PARAMETER_PROPERTIES NOTE: The values unitString unitDecimal or unitHex or unitPercent or unitCharacter or unitTime or unitTicks used with propValidUnits and propDefaultUnit are actual keywords and should be specified accordingly. NOTE: The keywords used to describe the properties ValidUnits, DefaultUnits, DefaultValue, List, Bound,  ShortDescription, FullDescription and Notes are prefixed by the word "prop" in this directive (e.g., propValidUnits. propDefaultUnit, etc.). This applies only to this directive. NOTE: The keywords used to describe the units Decimal, Hex, Percent, Character, Time and Ticks are prefixed by the word "unit" in this directive (e.g., unitDecimal. unitString, etc.). This applies only to this directive. Description: The parameter properties directive is used to restrict the behavior of parameters, similar to the way property sheets are used in SIMPL to modify the behavior of module parameters during data entry time (i.e. when a programmer is using the module and entering data into the parameter fields). The "parameter_variable" is the identical name used when declaring one of the 5 parameter types.  If the parameter is an array type, the [] notation is not used, just the name.  Multiple parameters may be given the same property block by listing them separated by commas. NOTE: If the variables are arrayed elements, the usual [ ] notation should not be used. The parameters that are introduced to SIMPL+ by this directive are similar in form and function to their existing namesakes. For example, SIGNED_INTERGER_PARAMETER possesses the same basic attributes as SIGNED_INTEGER. The new parameters are: Parameters: | | | |----|----| | Parameter | Similar to: | | Non-Arrayed | | | [INTEGER_PARAMETER] | [INTEGER] | | [SIGNED_INTEGER_PARAMETER] | [SIGNED_INTEGER] | | [LONG_INTEGER_PARAMETER] | [LONG_INTEGER] | | [SIGNED_LONG_INTEGER_PARAMETER] | [SIGNED_LONG_INTEGER] | | [STRING_PARAMETER] | [STRING] | | Arrayed | | | [INTEGER_PARAMETER] | [INTEGER] | | [SIGNED_INTEGER_PARAMETER] | [SIGNED_INTEGER] | | [LONG_INTEGER_PARAMETER] | [LONG_INTEGER] | | [SIGNED_LONG_INTEGER_PARAMETER] | [SIGNED_LONG_INTEGER] | | [STRING_PARAMETER] | [STRING] | NOTE: The STRING parameters only set properties for propDefaultValue, propList, propShortDescription, propFullDescription and propNotes. All other values will be ignored. The following values are set by this directive: Values: NOTE:  If the parameter variable specified in a property block is an array, the attributes in the block will be applied to all elements of the array. | Value | Description | | ------------- | ------------------ | | Parameter | Valid Unit Example | | unitDecimal | 25d | | unitHex | 25h | | unitPercent | 25% | | unitCharacter | 'A' | | unitTime | 25s | | unitTicks | 25t |

Therefore if propValidUnits=unitHex | unitDecimal, then only "h" and "d" constants would be accepted. Any others (e.g., 25%) would be rejected.  If nothing is specified, then this field should be assumed to be unitString|unitDecimal| unitHex|unitPercent|unitCharacter|unitTime| unitTicks (i.e. all types).

propDefaultUnits

This describes the behavior of what SIMPL will do with the parameter when a programmer types in a value and hits enter (without explicitly entering a type, i.e. they enter 25 and not 25d) or type in a value and move off the parameter field without typing a type.

STRING_PARAMETERs:  propDefaultUnits can only be set to unitString, however it is implied as it is the only legal value in this case.

All other parameter types:  propDefaultUnits is a subset of what is specified in propValidUnits, and must be one of unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks.  If this value is not specified, then it will be taken from–in the following order–propDefaultValue,  propBounds, propList and propValidUnits.

NOTE: This parameter must occur after propValidUnits or a compilation error will occur.

propDefaultValue

If this is a STRING_PARAMETER, it can be either left out or set to unitString. If this is a numeric parameter, it can be any bitwise OR separated list of a combination of any or all of unitString, unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks strings. These string units consist of a number suffixed with a single character or a single character surrounded by single quotes:

| Parameter | Valid Unit Example | | ------------- | ------------------ | | unitDecimal | 25d | | unitHex | 0x25 | | unitPercent | 25% | | unitCharacter | 'A' | | unitTime | 25s | | unitTicks | 25t |

NOTE: For unitHex, the value will actually appear as (in this example) 25h in SIMPL.  In SIMPL+ it must be specified with a leading '0x' and no 'h' suffix.

propList

This provides a drop-down list for a parameter. The list will show the contents of the "Label" field, but when compiled, the choice in the "Label" field is converted to the value specified in the appropriate Val field.   This directive is valid for all parameter types.

For example: if propList={0x25,"Address1"}, {0x26,"Address2"} then a drop-down list is shown containing 2 choices:  "Address1 [25h]" and "Address2 [26h]".  If the Address1 is chosen, when the program is compiled, the parameter passed is actually 25h.

The units for the values must be a unit that is expressed in the propValidUnits list.

NOTE:  Since the label field is in double quotes, spaces and commas are legal.

Values should be entered as show in the following table:

| Parameter | Valid Unit Example | | ------------- | ------------------ | | unitDecimal | 25d | | unitHex | 0x25 | | unitPercent | 25% | | unitCharacter | 'A' | | unitTime | 25s | | unitTicks | 25t |

NOTE: If propList and propBounds are both specified, propList will take priority and propBounds will be ignored.

NOTE: If a propList is used, a propDefaultValue may still be expressed, but it MUST be one of the values entered in the prop list.

NOTE: For unitHex, the value will actually appear as (in this example) 25h in SIMPL.  In SIMPL+ it must be specified with a leading '0x' and no 'h' suffix.

propBounds

This allows the programmer a range of values that can be typed in when using the parameter field by specifying upper_bound and lower_bound.

The units must be expressed in the propValidUnits list.  

This directive is not valid for STRING_PARAMETER types.

For example: If upper_bound=25d and lower_bound=1000d, then SIMPL will restrict the type-in values to between 25d and 1000d.

NOTE: For unitHex, the value will actually appear as (in this example) 25h in SIMPL.  In SIMPL+ it must be specified with a leading '0x' and no 'h' suffix.

propShortDescription

This provides a single string for the status bar hint in SIMPL and when ALT+F3 is performed on a parameter.

#BEGIN_PROP_FULL_DESCRIPTION

#END_PROP_FULL_DESCRIPTION

The text entered in this field becomes the Parameter Properties text and is a more elaborate description. This is only seen in SIMPL when the user performs an ALT+F3 on the parameter. Multiple lines can be entered.  

#BEGIN_PROP_NOTES

#END_PROP_NOTES

The text entered in this field becomes the Parameter Properties text and is a more elaborate description. This is only seen in SIMPL when the user performs an ALT+F3 on the parameter. Multiple lines can be entered.  

NOTE: Examples of valid and invalid parameter properties can be found [here]. NOTE: For propDefaultValue: if the user enters a value in a parameter field and then moves away from that field, the value will be assumed to be that of the specified units (if any). Therefore entering 26 in the field will assume 26 seconds if propDefaultUnit=unitTime, etc. NOTE: For propList: the Label field is contained in double quotes and therefore allowed to contain any character including spaces and commas. Example:    DIGITAL_INPUT trig;    INTEGER_PARAMETER DelayTime;    STRING_INPUT MyString[20];    STRING_PARAMETER DeviceCode[33]; #BEGIN_PARAMETER_PROPERTIES DelayTime    propValidUnits=unitTime|unitTicks    propBounds=25s,36s;    propDefaultValue=26s; #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES DeviceCode    propDefaultValue="35" #END_PARAMETER_PROPERTIES push trig {    String LocalString[50];    Delay(DelayTime);    LocalString = MyString + "Stuff" + DeviceCode;    print("the string is %s, The DeviceCode is %s", LocalString, DeviceCode); } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later Control System: 2 Series Only, CUZ 4.00 or later [INTEGER_PARAMETER]: ../Declarations/INTEGER_PARAMETER.md [LONG_INTEGER_PARAMETER]: ../Declarations/LONG_INTEGER_PARAMETER.md [SIGNED_INTEGER_PARAMETER]: ../Declarations/SIGNED_INTEGER_PARAMETER.md [SIGNED_LONG_INTEGER_PARAMETER]: ../Declarations/SIGNED_LONG_INTEGER_PARAMETER.md [STRING_PARAMETER]: ../Declarations/STRING_PARAMETER.md [INTEGER]: javascript:void(0); [SIGNED_INTEGER]: javascript:void(0); [LONG_INTEGER]: javascript:void(0); [SIGNED_LONG_INTEGER]: javascript:void(0); [STRING]: javascript:void(0); [here]: ../../Examples.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > ANALOG SERIAL EXPAND > #ANALOG_SERIAL_EXPAND -------------------------------------------------------------------------------- # #ANALOG_SERIAL_EXPAND Name: #ANALOG_SERIAL_EXPAND Syntax:     #ANALOG_SERIAL_EXPAND \ Description: This provides a way to expand, or add, inputs and/or outputs for a specified symbol. It is useful when you want to expand the number of outputs for a given input, expand the number of inputs for a specific output, expand both the inputs and outputs or for a variety of other combinations. NOTE: Expansion directives can only be used in conjunction with an array input. Values: | | | |----|----| | Value | Description | | Separately | This is the default value and allows for expansion of both inputs and outputs, in no particular order, on a given symbol. | | OutputsWithParams | This allows a single input to be expanded into a number of outputs. | | InputsWithOutputs | This allows the combined expansion of inputs and outputs. If you add an input, an output is also automatically added. | | InputsWithParams | This allows the expansion of the number of inputs for a single output. | | AllWithAny | This allows for the expansion of both inputs and outputs, but unlike InputWithOutputs, the relationship between inputs and outputs doesn't have to be one to one. | | PWithIxorO | This allows for the expansion of either inputs or outputs. | Example:     #ANALOG_SERIAL_EXPAND OutputsWithParameters A single input would be expanded into a specified number of outputs. Version: SIMPL+ Version 2.10.00 or later Control System: 2 Series Only -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > CATEGORY > #CATEGORY -------------------------------------------------------------------------------- # #CATEGORY Name: #CATEGORY Syntax:     #CATEGORY "\" Description: A Category is the name of the folder in the Logic Symbols library tree where the module is shown. To specify a category for a SIMPL+ module, the #CATEGORY directive must be used with a category specified in the list shown in the SIMPL+ Editor. Just click "Edit" then "Insert Category" for a list of categories. Choose one and the appropriate line of code is added to your SIMPL+ program.   Example:     #CATEGORY "6" // Lighting If a category ID does not exist in the Symbol Tree Category list, the SIMPL+ module will default to the Miscellaneous category type. Version: X Generation:  Not Supported 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > CRESTRON LIBRARY > #CRESTRON_LIBRARY -------------------------------------------------------------------------------- # #CRESTRON_LIBRARY Name: #CRESTRON_LIBRARY Syntax:     #CRESTRON_LIBRARY "\" Description: Directs the compiler to include code from a Crestron provided library. The module name specified is the Crestron Library Filename without the CSL extension. Example:     #CRESTRON_LIBRARY "SpecialIntegerFunctions" Directs the compiler to include the Crestron Library "SpecialIntegerFunctions.csl" from the Crestron SIMPL+ Archive. Version: X-Generation SIMPL v1.50.06 SIMPL v2.01.05 and later, Global variables can no longer be declared within Crestron Library (.csl) files. 2-Series SIMPL v2.01.05 and later [Same features as X Generation SIMPL v2.01.05] 3-Series SIMPL v4.00.00 and later 4-Series SIMPL v4.14.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > CRESTRON SIMPLSHARP LIBRARY > #CRESTRON_SIMPLSHARP_LIBRARY -------------------------------------------------------------------------------- # #CRESTRON_SIMPLSHARP_LIBRARY Name: #CRESTRON_SIMPLSHARP_LIBRARY Syntax:     #CRESTRON_SIMPLSHARP_LIBRARY "\" Description: Directs the compiler to include code from a Crestron SIMPL# library. The module name specified is the library filename without the CLZ extension. Example:     #CRESTRON_SIMPLSHARP_LIBRARY "MyCrestronLibrary" Directs the compiler to include the Crestron SIMPL# Library, "MyCrestronLibrary.clz". Version: 3-Series SIMPL v4.02.00 and later 4-Series SIMPL v4.14.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > DEFAULT NONVOLATILE > #DEFAULT_NONVOLATILE -------------------------------------------------------------------------------- # #DEFAULT_NONVOLATILE Name: #DEFAULT_NONVOLATILE Syntax:     #DEFAULT_NONVOLATILE Description: Program variables retain their value if hardware power is lost. The compiler will default all variables declared within the SIMPL+ module as nonvolatile. Individual variables can use the Volatile keyword to override this default. See also: [#DEFAULT_VOLATILE]. Example:     #DEFAULT_NONVOLATILE Version: X Generation:  Not Supported.  On X Generation Systems, all global variables are Non Volatile. 2-Series:  SIMPL v2.01.05 and later [#DEFAULT_VOLATILE]: _DEFAULT_VOLATILE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > DEFAULT VOLATILE > #DEFAULT_VOLATILE -------------------------------------------------------------------------------- # #DEFAULT_VOLATILE Name: #DEFAULT_VOLATILE Syntax:     #DEFAULT_VOLATILE Description: Program variables will not retain their value if hardware power is lost. The compiler will default all variables declared within the SIMPL+ module as volatile. Individual variables can use the Nonvolatile keyword to override this default. See also [#DEFAULT_NONVOLATILE.] Example:     #DEFAULT_VOLATILE Version: X Generation:  Not Supported.  On X Generation Systems, all global variables are Non Volatile. 2-Series:  SIMPL v2.01.05 and later [#DEFAULT_NONVOLATILE.]: _DEFAULT_NONVOLATILE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > DEFINE CONSTANT > #DEFINE_CONSTANT -------------------------------------------------------------------------------- # #DEFINE_CONSTANT Name: #DEFINE_CONSTANT Syntax:     #DEFINE_CONSTANT \ \ Description: Define a \ that will be substituted anywhere in the current source file where \ is used. Example:     #DEFINE_CONSTANT ETX 0x03     INTEGER I;     I=ETX; Assigns the value of 0x03 to the variable I. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > DIGITAL EXPAND > #DIGITAL_EXPAND -------------------------------------------------------------------------------- # #DIGITAL_EXPAND Name: #DIGITAL_EXPAND Syntax:     #DIGITAL_EXPAND \ Description: This provides a way to expand, or add, inputs and/or outputs for a specified symbol. It is useful when you want to expand the number of outputs for a given input, expand the number of inputs for a specific output, expand both the inputs and outputs or for a variety of other combinations. NOTE: Expansion directives can only be used in conjunction with an array input. Values: | | | |----|----| | Value | Description | | Separately | This is the default value and allows for expansion of both inputs and outputs, in no particular order, on a given symbol. | | OutputsWithParams | This allows a single input to be expanded into a number of outputs. | | InputsWithOutputs | This allows the combined expansion of inputs and outputs. If you add an input, an output is also automatically added. | | InputsWithParams | This allows the expansion of the number of inputs for a single output. | | AllWithAny | This allows for the expansion of both inputs and outputs, but unlike InputWithOutputs, the relationship between inputs and outputs doesn't have to be one to one. | | PWithIxorO | This allows for the expansion of either inputs or outputs. | Example:     #DIGITAL_EXPAND OutputsWithParameters InputsWithOutputs A single input would be expanded into a specified number of outputs. Version: SIMPL+ Version 2.10.00 or later Control System: 2-Series Only -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > ENABLE DYNAMIC > #ENABLE_DYNAMIC -------------------------------------------------------------------------------- # #ENABLE_DYNAMIC Name:   #ENABLE_DYNAMIC Syntax: #ENABLE_DYNAMIC Description: Required if the DYNAMIC keyword is used on variable definitions.   If DYNAMIC variables are not declared, this compiler directive can still be beneficial to use.  It will allow the compiler & runtime to make better use of memory by dynamically allocating internal temporary variables. Example: #ENABLE_DYNAMIC Version: X Generation:  Not supported 2-Series:  SIMPL v2.10.24 and later (Requires CUZ 4.000 or later) -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > ENABLE STACK CHECKING > #ENABLE_STACK_CHECKING -------------------------------------------------------------------------------- # #ENABLE_STACK_CHECKING Name:   #ENABLE_STACK_CHECKING Syntax: #ENABLE_STACK_CHECKING Description: Allow run-time stack checking to be performed on this  module.  If there is a stack overflow, you will see an error similar to: Module S-5 : ExampleSimpl+Code.umc at line 25: Stack overflow. Terminating Task. (space =xxxx) When a function is called, it adds memory to the stack. When the function returns, the memory is removed from the stack. However, if you have a recursive program or if inputs come in faster than they can be processed (i.e. the PUSH/CHANGE/EVENT function is called but does not finish and return), the stack may continue to grow. This option checks for a stack whose memory grows beyond that which is allocated. The default memory allocation is 4k. Refer to [#Large_Stack] to increase the stack size. NOTE: #ENABLE_STACK_CHECKING must be defined before all User-Defined functions are declared. Example: #ENABLE_STACK_CHECKING Version: X Generation:  Not supported 2-Series:  SIMPL v2.05.17 and later (Requires CUZ 3.080 or later). [#Large_Stack]: _LARGE_STACK.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > ENABLE TRACE > #ENABLE_TRACE -------------------------------------------------------------------------------- # #ENABLE_TRACE Name:   #ENABLE_TRACE Syntax: #ENABLE_TRACE Description: When invoked, this enables trace output. If it is not invoked no console output will be generated. Analogous to a debug mode when on, and a release mode when off. When #ENABLE_TRACE is "on" Trace statements are shown as Trace. When "off" Trace statements are not shown. NOTE: Shown as trace indicates formatting with special characters and seen in SIMPL Debugger Trace window as Trace Data. Version: X Generation:  Not supported 2-Series:  SIMPL v2.10.09 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > HELP > #HELP -------------------------------------------------------------------------------- # #HELP Name: #HELP Syntax:     #HELP "\" Description: Several #HELP lines can be specified. When F1 is hit either on the symbol in the Symbol Library, in either the Program View or the Detail view, the help text will be displayed. If this directive or the #HELP_BEGIN … #HELP_END directive is not present, the help text shown is "NO HELP AVAILABLE". Note that it is preferable to use the #HELP_BEGIN … #HELP_END directives rather than #HELP since it is easier to edit and read the code. Example:     #HELP "This is line 1 of my help text"     #HELP "This is line 2 of my help text" Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > HELP BEGIN … HELP END > #HELP_BEGIN … #HELP_END -------------------------------------------------------------------------------- # #HELP_BEGIN … #HELP_END Name: #HELP_BEGIN … #HELP_END Syntax:     #HELP_BEGIN     Help Text Line 1     Help Text Line 2     etc.     #HELP_END Description: The #HELP_BEGIN, #HELP_END pair makes it easier to create help since each line does not need a separate #HELP directive. When F1 is hit either on the symbol in the Symbol Library, in either the Program View or the Detail view, the help text will be displayed. If this directive or #HELP is not present, the help text shown is "NO HELP AVAILABLE". Note that the text will show up exactly as typed between the begin/end directives (including blank lines). Example:     #HELP_BEGIN     This is help line 1.     This is help line 3.     #HELP_END Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > HINT > #HINT -------------------------------------------------------------------------------- # #HINT Name: #HINT Syntax:     #HINT "Hint Text" Description: The #HINT shows up in the status bar and provides a short tactical clue as to the function of the symbol in the same way that Crestron-defined built-in symbols do. If the hint is specified, it will be visible when the symbol is highlighted in the User Modules section of the Symbol Library. The text shows up as the symbol name as it is stored on disk, followed by a colon, followed by the text. For example, a symbol with the name "My Symbol" might be stored on disk with the filename MYSYM.USP. If the hint is specified as #HINT "This is my symbol!" then the status bar will show "MYSYM.USP : This is my symbol!". If no #HINT is specified, then only the filename is shown. Example:     #HINT "This module controls a CNX-PAD8 Switcher" Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > IF DEFINED … ENDIF > #IF_DEFINED … #ENDIF -------------------------------------------------------------------------------- # #IF_DEFINED … #ENDIF Name: #IF_DEFINED … #ENDIF Syntax:     #IF_DEFINED \     \     #ENDIF Description: Results in compilation of the \ only if \ has previously been defined. This construct is generally useful for putting in code for debugging purposes, giving the ability to easily turn the debugging on and off during compilation. Example:     #DEFINE_CONSTANT DEBUG 1     DIGITAL_OUTPUT OUT$;     INTEGER I;     FOR(I=0 to 20)     {       #IF_DEFINED DEBUG         PRINT("Loop index I = %d\n", I);       #ENDIF       OUT$ = ITOA(I);     } The value of the loop is printed only if the DEBUG constant is defined. In order to prevent compilation of the code, delete the line that defines the constant or comment it out. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later See also [IsSignalDefined] [IsSignalDefined]: ../System_Interfacing/IsSignalDefined.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > IF NOT DEFINED … ENDIF > #IF_NOT_DEFINED … #ENDIF -------------------------------------------------------------------------------- # #IF_NOT_DEFINED … #ENDIF Name: #IF_NOT_DEFINED … #ENDIF Syntax:     #IF_NOT_DEFINED \     \     #ENDIF Description: Results in compilation of the \ only if \ has not been  previously defined. This construct is generally useful for putting in code for debugging purposes, giving the ability to easily turn the debugging on and off during compilation. Example:     #DEFINE_CONSTANT DEBUG 1     DIGITAL_OUTPUT OUT$;     INTEGER I;     FOR(I=0 to 20)     {       #IF_DEFINED DEBUG         PRINT("Loop index I = %d\n", I);       #ENDIF       #IF_NOT_DEFINED_DEBUG         OUT$ = ITOA(I);       #ENDIF     } The value of the loop is only printed if the DEBUG constant is defined. The output OUT$ is only generated if the debug constant is not defined (if debug mode is not turned on). In order to generate "release" code, the debug constant can be deleted or commented out. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > INCLUDEPATH > #INCLUDEPATH -------------------------------------------------------------------------------- # #INCLUDEPATH Name: #INCLUDEPATH Syntax:     #INCLUDEPATH "\" Description: Directs the compiler to search for User SIMPL+ and SIMPL# Libraries in the specified paths. The compiler will search for the library in the following order:    1)  Project Folder    2)  Global SIMPL+ Folder (refer to Edit | Preferences | Paths in SIMPL).    3)  Paths specified in #INCLUDEPATH compiler directive Example: #INCLUDEPATH "c:\\MyLibrares" #INCLUDEPATH "..\\..\\Projects\\bin"       #USER_LIBRARY "MySPlusLibrary"       #USER_SIMPLSHARP_LIBRARY "MySSharpLibrary" Version: 3-Series SIMPL v4.02.17 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > LARGE STACK > #LARGE_STACK -------------------------------------------------------------------------------- # #LARGE_STACK Name:   #LARGE_STACK Syntax: #LARGE_STACK Description: Increase the stack size.  Usually the default stack size is sufficient, unless heavy recursion is being done.  If you see an error similar to: Module S-5 : foobar.umc at line 25: Stack overflow. Terminating Task. (space =xxxx) You can try using the #LARGE_STACK directive, which increases the stack size to 8k.  If this does not help, the module should be checked for heavy recursion.  See [#Enable_Stack_Checking] to allow run-time stack checking to be performed on this module. In functions, only INTEGER declarations (not strings, string arrays, or integer arrays) are taken from the stack. NOTE: #LARGE_STACK must be defined before all User-Defined functions are declared. Example: #LARGE_STACK Version: X Generation:  Not supported 2-Series:  SIMPL v2.05.17 and later (Requires CUZ 3.080 or later) [#Enable_Stack_Checking]: _ENABLE_STACK_CHECKING.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > MAX INTERNAL BUFFER SIZE > #MAX_INTERNAL_BUFFER_SIZE -------------------------------------------------------------------------------- # #MAX_INTERNAL_BUFFER_SIZE Name:   #MAX_INTERNAL_BUFFER_SIZE Syntax: #MAX_INTERNAL_BUFFER_SIZE \ Description: 2-Series only.  Sets the maximum size in bytes for the compiler’s internal string allocations.  By default, the compiler will allocate 65535 bytes when using STRING_OUTPUT variables.  String arguments passed to User Functions may also result in a 65535 byte string allocation, depending the argument’s usage.   #MAX_INTERNAL_BUFFER_SIZE can be used to specify a different upper allocation limit.  The range can be from 1-65535. NOTE:  There are some conditions where this compiler directive can be useful:\ \ This compiler directive can be used to optimize the amount of memory used by a module.  Strings such as STRING_OUTPUTs and function arguments have unknown values, forcing the compiler to allocate the maximum buffer length of 65535 bytes.  If the approximate length is known for these types of variables, then this compiler directive can be used to specify a smaller amount.  \ \ Due to some compiler optimizations that Crestron has chosen to implement, the use of some strings may result in a runtime string buffer overflow.  This error might result in the following message, “String __FN_DST_STR__ overflow.”  Setting this compiler directive will replace the compiler’s assumed number of bytes with the number of bytes specified by the directive.\ \ This compiler directive is also useful for large modules and/or when many instances of a module are running simultaneously on the control system. Example: #MAX_INTERNAL_BUFFER_SIZE 10000 Version: X Generation:  Not supported 2-Series:  SIMPL v3.01.25 or later 3-Series:  N/A -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > OUTPUT SHIFT > #OUTPUT_SHIFT -------------------------------------------------------------------------------- # #OUTPUT_SHIFT Name: #OUTPUT_SHIFT Syntax:     #OUTPUT_SHIFT \ Description: This provides a way to arrange the inputs and outputs on the symbol graphic so that they line up and are easy to read. Example:     #OUTPUT_SHIFT 5 This would shift the outputs on a given symbol by five places. Version: SIMPL+ Version 2.10.00 or later Control System: 2 Series Only, CUZ 4.00 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > PRINT TO TRACE > #PRINT_TO_TRACE -------------------------------------------------------------------------------- # #PRINT_TO_TRACE Name:   #PRINT_TO_TRACE Syntax: #PRINT_TO_TRACE Description: When invoked, this converts all print statements to trace statements. Intended to be a quick way to convert all [Print] functions to the new [Trace] function. When #PRINT_TO_TRACE is "on" Print statements are shown as Trace. When "off" Print statements are shown as Console data. NOTE: Shown as console data indicates no additional formatting and may be seen in the Trace window as Console data. Version: X Generation:  Not supported 2-Series:  SIMPL v2.10.09 and later [Print]: ../String_Formatting_&_Printing_Functions/PRINT.md [Trace]: ../String_Formatting_&_Printing_Functions/TRACE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > SKIP > _SKIP_ -------------------------------------------------------------------------------- # _SKIP_ This allows a gap to be placed on the SIMPL+ symbol so chosen inputs and outputs can be made to line up visually. _SKIP_ can be used with parameters as well. This is a graphic consideration only and does not have an effect on the input and output relationships of the symbol. NOTE: The _SKIP_ keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT, STRING_OUTPUT, INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example: DIGITAL_INPUT osc_in, _SKIP_, toggle_in; ANALOG_OUTPUT an_level1, an_level2, _SKIP_, an_level3; LONG_INTEGER_PARAMETER temp_level_min, _SKIP_, temp_level_max; -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > SYMBOL NAME > #SYMBOL_NAME -------------------------------------------------------------------------------- # #SYMBOL_NAME Name: #SYMBOL_NAME Syntax:     #SYMBOL_NAME "\" Description: By specifying \, this name will show up on the header of the symbol in the detail view as well as in the USER SIMPL+ section of the Symbol Library. If this directive is not present, the default name shown in the Symbol Library/Program View/Detail view is the name of the USP file as saved on disk. For example, if the file is saved as "Checksum Program.USP", the tree views will show "Checksum Program" as the name. Example:     #SYMBOL_NAME "My SIMPL+ Program" Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > USER LIBRARY > #USER_LIBRARY -------------------------------------------------------------------------------- # #USER_LIBRARY Name: #USER_LIBRARY Syntax:     #USER_LIBRARY "\" Description: Directs the compiler to include code from a User written library. The module name specified is the User Library Filename without the USL extension that is used by User Libraries. Relative or absolute path are not allowed within this directive (see #INCLUDEPATH). The compiler will search for the library in the following order:    1)  Project Folder    2)  Global SIMPL+ Folder (refer to Edit | Preferences | Paths in SIMPL).    3)  Paths specified in #INCLUDEPATH compiler directive Example:     #USER_LIBRARY "MyFunctions" Directs the compiler to include the User Library "MyFunctions.usl" from the User SIMPL+ directory. User libraries can be created by saving a SIMPL+ module as type SIMPL+ library, instead of the default SIMPL+ file. Version: X-Generation SIMPL v1.50.06 SIMPL v2.01.05 and later, Global variables can no longer be declared within User Library (.usl) files. 2-Series SIMPL v2.01.05 and later [Same features as X Generation SIMPL v2.01.05] 3-Series SIMPL v4.00.00 and later 4-Series SIMPL v4.14.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > USER SIMPLSHARP LIBRARY > #USER_SIMPLSHARP_LIBRARY -------------------------------------------------------------------------------- # #USER_SIMPLSHARP_LIBRARY Name: #USER_SIMPLSHARP_LIBRARY Syntax:     #USER_SIMPLSHARP_LIBRARY "\" Description: Directs the compiler to include code from a User SIMPL# library. The module name specified is the library filename without the CLZ extension. Relative or absolute path are not allowed within this directive (see #INCLUDEPATH). The compiler will search for the library in the following order:    1)  Project Folder    2)  Global SIMPL+ Folder (refer to Edit | Preferences | Paths in SIMPL).    3)  Paths specified in #INCLUDEPATH compiler directive Example:     #USER_SIMPLSHARP_LIBRARY "MyLibrary" Directs the compiler to include the User SIMPL# Library, "MyLibrary.clz". Version: 3-Series SIMPL v4.02.00 and later 4-Series SIMPL v4.14.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > rlt1D5 > Compiler Directives Overview -------------------------------------------------------------------------------- # Compiler Directives Overview Compiler directives are used by the SIMPL+ compiler to control attributes of the symbol without generating actual SIMPL+ code. They come at the beginning of the program, and are used to provide explicit instructions to the compiler. As such, directives are not part of the SIMPL+ language itself and are distinguished from actual SIMPL+ code by the pound sign (#) preceding their names. Compiler directives are provided in the template file that is created when a new program is started. The compiler directives are as follows: | | | |----|----| | Directive | Description | | [#ANALOG_SERIAL_EXPAND] | This provides a way to expand, or add, inputs and/or outputs for a specified symbol. | | [#BEGIN_PARAMETER_PROPS, #END_PARAMETER_PROPS] | This directive is used to declare parameter properties. | | [#CATEGORY] | A Category is the name of the folder in the Logic Symbols library tree where the module is shown. | | [#CRESTRON_LIBRARY] | Directs the compiler to include code from a Crestron provided library. | | [#DEFAULT_NONVOLATILE] | Program variables retain their value if hardware power is lost. | | [#DEFAULT_VOLATILE] | Program variables will not retain their value if hardware power is lost. | | [#DEFINE_CONSTANT] | Define a \ that will be substituted anywhere in the current source file where \ is used. | | [#DIGITAL_EXPAND] | This provides a way to expand, or add, inputs and/or outputs for a specified symbol. | | [#ENABLE_STACK_CHECKING] | Allows run-time stack checking to be performed on a given module.  If there is a stack overflow, an error will be produced. | | [#HELP] | Several #HELP lines can be specified. | | [#HELP_BEGIN … #HELP_END] | The #HELP_BEGIN, #HELP_END pair makes it easier to create help since each line does not need a separate #HELP directive. | | [#HINT] | The #HINT shows up in the status bar and provides a short tactical clue as to the function of the symbol in the same way that Crestron-defined built-in symbols do. | | [#IF_DEFINED … #ENDIF] | Results in compilation of the \ only if \ has not been  previously defined. | | [#IF_NOT_DEFINED … #ENDIF] | Results in compilation of the \ only if \ has not been  previously defined. | | [#LARGE_STACK] | This is used to increase the stack size when necessary. | | [#OUTPUT_SHIFT] | This provides a way to arrange the inputs and outputs on the symbol graphic so that they line up and are easy to read. | | [#SYMBOL_NAME] | By specifying \, this name will show up on the header of the symbol in the detail view as well as in the USER SIMPL+ section of the Symbol Library. | | [#USER_LIBRARY] | Directs the compiler to include code from a User written library. | [#ANALOG_SERIAL_EXPAND]: _ANALOG_SERIAL_EXPAND.md [#BEGIN_PARAMETER_PROPS, #END_PARAMETER_PROPS]: _BEGIN_PARAMETER_PROPS.md [#CATEGORY]: _CATEGORY.md [#CRESTRON_LIBRARY]: _CRESTRON_LIBRARY.md [#DEFAULT_NONVOLATILE]: _DEFAULT_NONVOLATILE.md [#DEFAULT_VOLATILE]: _DEFAULT_VOLATILE.md [#DEFINE_CONSTANT]: _DEFINE_CONSTANT.md [#DIGITAL_EXPAND]: _DIGITAL_EXPAND.md [#ENABLE_STACK_CHECKING]: _ENABLE_STACK_CHECKING.md [#HELP]: _HELP.md [#HELP_BEGIN … #HELP_END]: _HELP_BEGIN_…__HELP_END.md [#HINT]: _HINT.md [#IF_DEFINED … #ENDIF]: _IF_DEFINED_…__ENDIF.md [#IF_NOT_DEFINED … #ENDIF]: _IF_NOT_DEFINED_…__ENDIF.md [#LARGE_STACK]: _LARGE_STACK.md [#OUTPUT_SHIFT]: _OUTPUT_SHIFT.md [#SYMBOL_NAME]: _SYMBOL_NAME.md [#USER_LIBRARY]: _USER_LIBRARY.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Directives > rlt1D6 > #BEGIN_PARAMETER_PROPS, #END_PARAMETER_PROPS -------------------------------------------------------------------------------- # #BEGIN_PARAMETER_PROPS, #END_PARAMETER_PROPS Name: #BEGIN_PARAMETER_PROPS, #END_PARAMETER_PROPS Syntax:     #BEGIN_PARAMETER_PROPERTIES parameter_variable, parameter_variable    //propValidUnits=//unitString or unitDecimal|unitHex|unitPercent|unitCharacter|unitTime|unitTicks    // propDefaultUnit=//unitString or unitDecimal|unitHex|unitPercent|unitCharacter|unitTime|unitTicks    // propDefaultValue=    // propList=//{ "value","label" },{ "value","label" }    // propLowerBound=lower_bound    // propUpperBound=lower_bound    // propShortDescription=    // propFullDescription=    // propNotes= #END_PARAMETER_PROPERTIES NOTE: The keywords used to describe the properties ValidUnits, DefaultUnits, DefaultValue, List, LowerBound, UpperBound, ShortDescription, FullDescription and Notes are prefixed by the word "prop" in this directive (e.g., propValidUnits. propDefaultUnit, etc.). This applies only to this directive. NOTE: The keywords used to describe the units Decimal, Hex, Percent, Character, Time and Ticks are prefixed by the word "unit" in this directive (e.g., unitDecimal. unitString, etc.). This applies only to this directive. Description: This directive is used to declare parameter properties that don't change at runtime. The parameter, variables and properties to be declared, immediately follow the #BEGIN_PARAMETER_PROPS directive. The values of the parameter properties are set between the #BEGIN_PARAMETER_PROPS and #END_PARAMETER_PROPS directives. NOTE: If the variables are arrayed elements, the usual [ ] notation should not be used. The parameters that are introduced to SIMPL+ by this directive are similar in form and function to their existing namesakes. For example, SIGNED_INTERGER_PARAMETER possesses the same basic attributes as SIGNED_INTEGER. The new parameters are: Parameters: | | | |-------------------------------|-----------------------| | Parameter | Similar to: | | Non-Arrayed | | | INTEGER_PARAMETER | [INTEGER] | | SIGNED_INTEGER_PARAMETER | [SIGNED_INTEGER] | | LONG_INTEGER_PARAMETER | [LONG_INTEGER] | | SIGNED_LONG_INTEGER_PARAMETER | [SIGNED_LONG_INTEGER] | | STRING_PARAMETER | [STRING] | | Arrayed | | | INTEGER_PARAMETER | [INTEGER] | | SIGNED_INTEGER_PARAMETER | [SIGNED_INTEGER] | | LONG_INTEGER_PARAMETER | [LONG_INTEGER] | | SIGNED_LONG_INTEGER_PARAMETER | [SIGNED_LONG_INTEGER] | | STRING_PARAMETER | [STRING] | NOTE: The STRING parameters only set properties for propDefaultValue, propList, propShortDescription, propFullDescription and propNotes. All other values will be ignored. The following values are set by this directive: Values: | Value | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | propDefaultValue | This is the default value that will be shown in the parameter field in SIMPL. If there is no default value specified, there will be no default value shown in SIMPL. If the variable is an array, then this will be used for all parameters. | | propDefaultUnit | This can be unitString, unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks depending on the parameter being declared. If this value is not specified, then it will be taken from–in the following order–propDefaultValue, propList (val1), propLowerBound and propUpperBound. | | propValidUnits | This is a comma-separated list of a combination of any or all of unitString, unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks strings. (e.g., if propValidUnits=unitHex, unitDecimal, then only "h" and "d" constants would be accepted. Any others (e.g., 25%) would be rejected. If nothing is specified, then this field should be assumed to be: unitString, unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks. | | propList | This provides a drop-down list for a parameter. The list will show the contents of the "Label" field, but when compiled, the choice in the "Label" field is converted to the value specified in the appropriate Val field. For example: if propList=25h,"Address1",26h,"Address2" then a drop-down list is shown containing 2 choices: Address1 and Address2. If the Address1 is chosen, when the program is compiled, the parameter passed is actually 25h. If propList and propUpperBound/propLowerBound are both specified, propList will take priority and propUpperBound/propLowerBound will be ignored. | | propUpperBound, propLowerBound | Although a legal range of values is implied by the type of parameter being used, it is possible to further restrict that range by specifying propUpperBound and/or propLowerBound. | | propShortDescription | Text entered in this field, contained within double quotes, becomes the status bar hint in SIMPL. | | propFullDescription | The text entered in this field, contained within double quotes, becomes the Parameter Properties text. | | propNotes | The text entered in this field, contained within double quotes, becomes the Parameter Properties text. | NOTE: For propDefaultValue: if the user enters a value in a parameter field and then moves away from that field, the value will be assumed to be that of the specified units (if any). Therefore entering a 5 in the field will assume 5 seconds if propDefaultUnit=unitTime, etc. NOTE: For propList: the Label field is contained in double quotes and therefore allowed to contain any character including spaces and commas. Example:     DIGITAL_INPUT trig;    INTEGER_PARAMETER DelayTime;    STRING_INPUT MyString[20];    STRING_PARAMETER DeviceCode[33]; #BEGIN_PARAMETER_PROPS DelayTime    propDefaultValue=5s    propValidUnits=unitTime,unitTicks    propUpperBound=25s    propLowerBound=36s #END_PARAMETER_PROPS #BEGIN_PARAMETER_PROPS DeviceCode    propDefaultValue="35" #END_PARAMETER_PROPS push trig {    String LocalString[50];    Delay(DelayTime);    LocalString = MyString + "Stuff" + DeviceCode;    print("the string is %s, The DeviceCode is %s", LocalString, DeviceCode); } Version: SIMPL+ Version 3.03.00 or later Control System: 2 Series Only, CUZ 4.00 or later [INTEGER]: javascript:void(0); [SIGNED_INTEGER]: javascript:void(0); [LONG_INTEGER]: javascript:void(0); [SIGNED_LONG_INTEGER]: javascript:void(0); [STRING]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1000 -------------------------------------------------------------------------------- # Compiler Error 1000 syntax error:  '\' already defined The specified identifier was declared more than once.  A variable can only be declared once within it’s function scope.  The same identifier cannot be used for more than one declaration type. NOTE: Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. - Make sure the identifier has not been declared as another declaration type, user-defined function, or structure definition. The following are examples of this error: INTEGER i; INTEGER i;        // error – i is already defined as an INTEGER STRING i[100];    // error – i is already defined as an INTEGER STRUCTURE myStruct {    INTEGER i;     // ok – i is a member variable of myStruct } INTEGER_FUNCTION MyFunc( INTEGER x, INTEGER y ) {    INTEGER i;     // ok    INTEGER i;     // error - i is already defined as a local INTEGER    INTEGER x;     // error – x is already defined as a function                   //         parameter, which makes it a local                   //         variable in this function } FUNCTION MyFunc() // error – MyFunc() is already defined                   //         as an INTEGER_FUNCTION { } FUNCTION AnotherFunc( INTEGER x, INTEGER y  ) // ok – x and y are                                               // local to this function { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1001 -------------------------------------------------------------------------------- # Compiler Error 1001   syntax error:  Undefined variable: '\'                                 Undefined function ‘\’ The specified identifier was not declared. All variables and user-defined functions must be declared before they are used.  They must be declared either globally or within the same function scope.  Variables from one program are not accessible from another program. NOTE: Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. -  Make sure the identifier is spelled correctly -  Make sure the identifier has not been declared locally within another function -  When using structures, make sure the proper ‘dot’ notation is being used when accessing the structure’s variables (see example below) The following are examples of this error: INTEGER i; STRUCTURE myStruct {    INTEGER structMember;    INTEGER structArrMember[10]; } myStruct struct; myStruct structArr[10]; FUNCTION MyFunc( INTEGER x ) {    INTEGER k;    i = 1;                               // ok    k = 3;                               // ok    x = 4;                               // ok    struct.structMember = 5;             // ok – proper ‘dot’ notation    struct.structMember[1] = 6;          // ok – proper ‘dot’ notation    structArr[1].structMember = 7;       // ok – proper ‘dot’ notation    structArr[1].structArrMember[2] = 8; // ok – proper ‘dot’ notation    j = 2;                  // error – j is not declared    structMember = 10;      // error – improper ‘dot’ notation    structMember[1] = 11;   // error – structMember is not an array    k = AnotherFunc();      // error – AnotherFunc() was not                            //         declared previously } INTEGER_FUNCTION AnotherFunc() {    k = 5;             // error – k is a local variable of MyFunc()    x = 6;             // error – x is a local variable of MyFunc()    Call MyFunc();     // ok    Call MyFunk();     // error – spelling error    return (1); } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1002 -------------------------------------------------------------------------------- # Compiler Error 1002 syntax error:  Missing '\' A language element was expected and not found.  The compiler expects certain language elements to appear before or after other elements.  If any other language element is used, the compiler cannot understand the statement.  Examples are missing parenthesis after a function call, missing semicolons after a statement and missing braces when defining functions. NOTE:  A token is a language element such as a keyword or operator. Anything that is not whitespace (i.e.:  spaces, tabs, line feeds and comments) is a token. - Examine the last uncommented non-blank line or statement within the program.  If a token was required in a previous statement and was not encountered, the compiler will continue onto the next line and mark the first token of the new statement as the error. The following are examples of this error: STRUCTURE MyStruct {    INTEGER x;    STRING s[100]; } MyStruct struct;         // error – missing ‘;’ from preceding                          //         structure definition INTEGER_FUNCTION MyFunc( INTEGER ) // error – argument variable                                    //         not specified    INTEGER x;            // error – ‘{’ missing before INTEGER    Print “abc”;          // error – missing parenthesis                          //         should be Print (“abc” );    // printing…    Print “def”           // error – error message will occur on                          //         next statement    // more printing…    Print “ghi”;          // error – missing ‘;’from preceding Print                          //         statement    x = ((1+2) + 3;       // error – unmatched set of parentheses    x = atoi( “abc”, 1 ); // error – atoi() does not take 2 arguments    if ( x = 4 )       return 5;          // error – should be return (5);    return (6);           // ok } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1003 -------------------------------------------------------------------------------- # Compiler Error 1003 syntax error:  Incorrect type '\', expected type(s):                                                   '\'                          Incorrect type, expected type(s):                                                   '\' A specific variable or type was expected and not found.  Examples are variables of one type being used in place of another, and incorrect variable types within function arguments. The following are examples of this error: STRING_FUNCTION MyFunc( INTEGER x ) {       INTEGER y;    x = getc( y );   // error – y is not of type STRING    x = MyFunc( 1 ); // error – x cannot accept the resulting string                     //         returned from MyFunc() } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1004 -------------------------------------------------------------------------------- # Compiler Error 1004 syntax error:  Unmatched symbol: '\' Some language constructs are composed of more than one keyword.  In these cases, each keyword may require statements before and after it is used. For example, the Switch statement uses the following keywords, Switch, Case, and Default.  If the keyword, Case, is encountered before or outside of switch statement, this error will result. The following are examples of this error: FUNCTION MyFunc( INTEGER x ) {       x = 1;    while ( 1 )    {       x = x + 1;    } until ( x \> 5 ); // error – ‘until’ is not part of the                       //         ‘while’ construct    else               // error – no preceding ‘if’ statement    {       x = 0;    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1005 -------------------------------------------------------------------------------- # Compiler Error 1005 syntax error:  Unexpected symbol in compiler directive:  '\' An invalid identifier is following a compiler directive. The following are examples of this error: #DEFINE_CONSTANT   MyIntConst   100  // ok #DEFINE_CONSTANT  “MyIntConst”  100  // error – MyIntConst should not                                      //         be in quotes – this                                      //         will be evaluated as                                      //         a literal string -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1006 -------------------------------------------------------------------------------- # Compiler Error 1006 syntax error:  Invalid #DEFINE_CONSTANT value: '\' The value for a #DEFINE_CONSTANT compiler directive must be either a literal string or an integer value.  Expressions, variables, functions and events cannot be specified as the compiler directive’s value. The following are examples of this error: INTEGER x; #DEFINE_CONSTANT  MyIntConst    100       // ok #DEFINE_CONSTANT  MyStrConst    “abc”     // ok #DEFINE_CONSTANT  MyExprConst   (1+2)     // error – expressions are                                           //         not allowed #DEFINE_CONSTANT  MyVarConst    x         // error – substitutions are                                           //         not allowed #DEFINE_CONSTANT  MyExprConst   (x+1)     // error – macros are not                                           //         supported #DEFINE_CONSTANT  MyFuncConst   myFunc    // error #DEFINE_CONSTANT  MyFuncConst   getc      // error -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1007 -------------------------------------------------------------------------------- # Compiler Error 1007 syntax error:  Missing array index: '\' A variable declared as an array is being used within an expression without the array index being specified.  For two-dimensional arrays, both indices must be specified.  When passing entire arrays as function arguments, no index is needed. The following are examples of this error: FUNCTION MyFunc() {       INTEGER i, arr[10], arr2[10][20];    STRING str[100], str2[100][50];    i = arr[5];                       // ok    i = arr2[5][10];                  // ok    arr[5] = arr2[5][10];             // ok    arr2[5][10] = 5;                  // ok    i = arr;                          // error – no index specified    arr = 5;                          // error – no index specified    i = arr2[5];                      // error – 2nd index not specified    str2[5] = “a”;                    // ok    str[5] = “a”;                     // error – ‘str’ is not an array } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1008 -------------------------------------------------------------------------------- # Compiler Error 1008 syntax error:  Invalid integer argument or undefined variable: '\' The construct being used requires either an integer value or variable passed as a function argument. - Make sure the variable has been declared The following are examples of this error: STRUCTURE MyStruct {    INTEGER x;    STRING s[100]; } MyStruct struct; Function MyFunc() {    INTEGER i;    STRING s[100];    for ( i = 1 to 10 )        // ok    {       for ( j = 1 to 5 )      // error – ‘j’ has not been declared       {          x = j;               // error – should be struct.x = j;       }       for ( s = “a” to “z” )  // error – strings are not allowed       {       }    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1009 -------------------------------------------------------------------------------- # Compiler Error 1009 syntax error:  Missing structure member: '\'                          Structure does not contain member: '\' Variables contained within structures are required when using structures within an expression or statement.  When using structures, the ‘dot’ notation is required to specify a structure’s variable. The notation is as follows:  \.\ Structure arrays are as follows:  \[index].\ The following are examples of this error: STRUCTURE MyStruct {    INTEGER x;    INTEGER x2[10]; } Function MyFunc( INTEGER x ) {    INTEGER i;    MyStruct struct;    MyStruct structArr[10];    i = struct.x;                  // ok    struct.x = 5;                  // ok    struct.x2[2] = 5;              // ok    structArr[1].x2[2] = 5;        // ok    Call MyFunc( i );              // ok    Call MyFunc( struct.x );       // ok    Call MyFunc( structArr[1].x ); // ok    Call MyFunc( struct.x2[1] );   // ok    i = struct;             // error – structure variable not specified    struct = i;             // error – structure variable not specified    Call MyFunc( struct );  // error – structure variable not specified    i = struct.z;           // error – structure variable does not exist    struct.z = 5;           // error – structure variable does not exist } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1010 -------------------------------------------------------------------------------- # Compiler Error 1010 syntax error:  Symbol Name contains illegal character: ';' The compiler directive, #SYMBOL_NAME, cannot contain a semicolon as part of the symbol name. The following are examples of this error: #SYMBOL_NAME “MySymbol”             // ok #SYMBOL_NAME “My Symbol”            // ok #SYMBOL_NAME “MySymbol;YourSymbol”  // error -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1011 -------------------------------------------------------------------------------- # Compiler Error 1011 syntax error:  Missing return value The Return statement requires a valid value or expression when used inside of functions that return a value (INTEGER_FUNCTION, STRING_FUNCTION, etc.).  The Return statement is available for functions that don’t return a value (FUNCTION), but do not allow values to be returned. The following are examples of this error: FUNCTION MyFunc( INTEGER x ) {    if ( x=1 )       return;      // ok – MyFunc() does not return a value    return (5);     // error – MyFunc is declared as FUNCTION and                    //         cannot return a value } INTEGER_FUNCTION AnotherFunc( INTEGER x ) {    if ( x=1 )       return;      // error – MyFunc is declared as an INTEGER_FUNCTION                    //         and must return a value    else if ( x=2 )       return (5);  // ok    else if ( x=3 )       return ();   // error – no value or expression is given    return (x);     // ok } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1012 -------------------------------------------------------------------------------- # Compiler Error 1012 syntax error:  Unterminated string constant A literal string was used and was not contained within quotes.   If a quotation character is needed within a literal string, a backslash should be placed before the quotation character (i.e.:  \\).  This will indicate to the compiler that the quotation character is not the terminating quote for the literal string. The following are examples of this error: FUNCTION MyFunc() {    Print( "%s", "abc\\" );  // ok    Print( "%s", "abc\\ );   // error - \\ is not a closing quote -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1013 -------------------------------------------------------------------------------- # Compiler Error 1013 syntax error:  Source code does not evaluate to anything A statement must perform an action in order to be valid.  If no action is specified, the statement will not be useful to the program. The following are examples of this error: FUNCTION MyFunc() {    INTTEGER x;    STRING str[100];    x = 5;       // ok    str = “abc”; // ok    x;           // error    str;         // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1014 -------------------------------------------------------------------------------- # Compiler Error 1014 syntax error:  Invalid Parameter:  \<’parameter_variable’\>                            Missing Parameters in directive construct The compiler was expecting a parameter type variable and another declaration type or token was found. The following are examples of this error: INTEGER_PARAMETER iParam; #BEGIN_PARAMETER_PROPERTIES // error – no parameter was                                        specified propDefaultUnit = unitDecimal; #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam // ok – iParam is a declared                                            parameter propDefaultUnit = unitDecimal; #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1015 -------------------------------------------------------------------------------- # Compiler Error 1015 syntax error:  Invalid Parameter Unit(s): '\' The compiler was expecting a parameter unit and another token or type was found. The following are examples of this error: INTEGER_PARAMETER iParam, iAnotherParam; #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal | unitHex |                     unitPercent | unitCharacter |                     unitTime | unitTicks; // ok propDefaultUnit = unitDecimal // ok propDefaultUnit = unitString; // error – unitString is not a                                   valid Parameter Unit #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1016 -------------------------------------------------------------------------------- # Compiler Error 1016 syntax error:  Invalid Parameter Property or                           #END_PARAMETER_PROPERTIES not                            found  \<’parameter_property’\> The compiler was expecting a parameter property and another token or type was found. The following are examples of this error: INTEGER_PARAMETER iParam, iAnotherParam; #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal|unitHex;    propDefaultUnit = unitDecimal; // ok –unitDecimal is a valid                                          Parameter Property. propDefaultValue = 10d; propList = {10d, "value1"}, {20d, "value2" }; propBounds = 1d, 20d; propShortDescription = "a short description"; propFullDescription = "a full description....."; propNotes = "Here's the notes"; Integer i; // error – Integer is not               A valid Parameter Property // #END_PARAMETER_PROPERTIES // error – comment line #END_PARAMETER_PROPERTIES // ok -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1017 -------------------------------------------------------------------------------- # Compiler Error 1017 **syntax error:**  **SIMPL# Classes and Structures are case-sensitive: ** **                           ‘\’** All code within SIMPL# Libraries is case-sensitive, therefore upper case and lower case characters are distinct. All class, structure and variable calls and references from SIMPL+ must use the same case as that used within the SIMPL# code. The datatype (class or structure name) and class/structure members within the SIMPL# Library are case-sensitive. The variable declared within the SIMPL+ module is not case-sensitive. For example, the classes, ‘MyClass’ and ‘myClass’ are different. The following are examples of this error: SIMPL# Library // SimplSharpLibrary.clz public class MyClass {    public int intVar;    public int IntFunction(); } public struct tagMyStruct {    public string myString; } SPlusModule.usp // UserModule.usp #USER_SIMPLSHARP_LIBRARY "SimplSharpLibrary" MyClass class1;         // ok – matching case myclass class2;         // error – case doesn’t match tagMyStruct myStruct1;  // ok – matching case TagmyStruct myStruct2;  // error – case doesn’t match FUNCTION MyFunction ( STRING str ) {    class1.intVar = 1; // ok – intVar is the same case    CLASS1.intVar = 2; // ok – CLASS1 is not case-sensitive.                               It is the variable declared                               within SIMPL+ (not SIMPL#).                               intVar is case-sensitive since                               it is a SIMPL# structure                               member.    myfunction( myStruct1.myString ); // ok, myfunction is a                                             function declared within                                             SIMPL+    class1.INTFUNCTION(); // error – INTFUNCTION is case-sensitive.                                     Should be IntFunction } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1100 -------------------------------------------------------------------------------- # Compiler Error 1100 fatal error:  Statement outside of function scope User-defined functions, Events, and compiler directives can only be defined at a global level. NOTE: Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. Variables can have either a global or local scope. The following are examples of this error: INTEGER i; STRING str[100]; #DEFINE_CONSTANT  myConst  1  // ok #DEFINE_CONSTANT  myConst  2; // error – semicolon is not needed i = 5;         // error – variables can only be used within a                // function or event Call MyFunc(); // error – functions can only be called from                //         another function or event ;              // error – a semicolon is valid statement (which                //         does nothing), and is not contained                //         within a function or event {              // error – braces only signify a group of                // statements within a function or                // construct (i.e.: if-else, while, etc)    INTEGER x;    INTEGER y; } Print( “outside of everything” ); // error – statement is                                   // not contained within                                   // a function or event FUNCTION MyFunc()                 // ok { } Function Main()     // ok – Function Main gets called automatically                     //      at the start of the program {    i = 5;           // ok    str = “”;        // ok    Call MyFunc();   // ok } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1101 -------------------------------------------------------------------------------- # Compiler Error 1101 fatal error:  Abort - Error count exceeded \ When compiling, if the error count is too large, the compiler will terminate the compile process prematurely.  This can not only be a tremendous time saver, but also help reduce the aggravation and stress levels of the programmer. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1200 -------------------------------------------------------------------------------- # Compiler Error 1200 expression error:  Invalid numeric expression: '\'                                    Invalid string expression                                    Invalid expression: '\' Expressions can be calculations, comparisons, or the validity of a value from a string or numeric variable or value.  All expressions require that all variables and values within the equation are of the same type.  For example, you cannot add or compare an integer and a string together.  The result of a comparison (i.e.: “abc” = “def”) is always a numeric value and will be treated as a numeric expression. The following are examples of this error: INTEGER x, y; STRING str[100]; INTEGER_FUNCTION myFunc( INTEGER i ) {    x = (1 + 2);                          // ok    if ( x \> y )                          // ok    {       if ( i )                           // ok       {          if ( str = “abc” )              // ok          {             while ( 1 )                  // ok             {                x = x + y + myFunc(1);    // ok                break;             }          }       }    }    return (1); } INTEGER_FUNCTION AnotherFunc( INTEGER i ) {    x = (1 + str);                 // error – cannot add an integer                                   //         and string    if ( x \> “abc” )               // error – cannot compare an integer                                   //         and string    {       if ( str )                  // error – cannot check the validity                                   //         of a string       {          if ( str = MyFunc(1) )   // error – cannot add strings                                   //         and integers together          {             while ( str \< “abc” ) // ok             {                x = (x + );        // error – incomplete expression                break;             }          }       }    }    return (1); } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1201 -------------------------------------------------------------------------------- # Compiler Error 1201 expression error:  Invalid \\x sequence                                Invalid \\x sequence: '\' A hexadecimal sequence within a literal string contained an invalid format.  Characters represented by a hexadecimal number must follow the format:  \xXX, where ‘\x’ signifies that a hexadecimal sequence is to follow and XX is the 2 digit hexadecimal value. The following are examples of this error: Function myFunc() {    STRING str[100];    MakeString( str, “Sending commands \xFF” );         // ok    MakeString( str, “Sending commands \x41\x1A\xFF” ); // ok    MakeString( str, “Sending cmd \x4” );  // error – 2 digits required    MakeString( str, “Sending cmd \x” );   // error – hex code expected    MakeString( str, “Sending cmd \xZZ” ); // error – invalid hex code    MakeString( str, “Sending cmd \xZZ” ); // error – invalid hex code } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1300 -------------------------------------------------------------------------------- # Compiler Error 1300 declaration error:  Array size missing                                  Array size invalid STRING, STRING_INPUT and BUFFER_INPUT variables require a valid length.  A length is specified by number enclosed within brackets.  Arrays for these datatypes are specified by the first set of brackets containing the number of strings and the second set of brackets containing the total length for each string.  Two-dimensional arrays are not allowed for these datatypes. In a function’s argument list, since all strings are passed by reference, no array size is necessary.  A string array is indicated by an empty set of brackets.  See example below. The following are examples of this error: #DEFINE_CONSTANT   ARR_SIZE   100 STRING str[100];                 // ok – str has a length of 100 STRING_INPUT strIn[ARR_SIZE];    // ok – strIn has a length of 100 BUFFER_INPUT bufIn[ARR_SIZE];    // ok – bufIn has a length of 100 STRING strArr[50][100];          // ok – 51 strings of length 100 STRING_INPUT strIn[50][100];     // ok - 51 strings of length 100 BUFFER_INPUT bufIn[50][100];     // ok – 51 strings of length 100 STRING_OUTPUT strOut;            // ok – STRING_OUTPUTs do not                                  //      require a length STRING_OUTPUT strOutArr[10];     // ok – array of 10 STRING_OUTPUTs STRING str2;                     // error – no length specified STRING_INPUT strIn;              // error – no length specified BUFFER_INPUT bufIn;              // error – no length specified STRING_OUTPUT strOutArr[10][20]; // error – 2-D arrays not supported STRING str[x];                   // error – variables are not allowed STRING str[myFunc()];            // error – function calls are                                  //         not allowed FUNCTION myFunc( STRING sArg,       // ok – strings are passed by                  STRING sArgArr[] ) //      reference. sArg is a                                     //      string and sArgArr is a                                     //      string array { } FUNCTION myFunc2( STRING sArg[10],     // error – size is not allowed                   STRING sArgArr[][] ) // error – 2-D strings not                                        //         supported { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1301 -------------------------------------------------------------------------------- # Compiler Error 1301 declaration error:  Invalid array index An index is required when accessing any element of an array.  Two dimensional arrays require both indices of the array to be specified.  This index must be a valid numeric expression. All arrays are passed to functions by reference, so specifying an index in this case is not allowed. The following are examples of this error: INTEGER xArr[10], x2dArr[10][20]; // ok STRING str[100], strArr[50][100]; // ok STRING_INPUT strIn[100];          // ok STRING_OUTPUT strOut;             // ok STRING str;                       // error – no length specified STRING_INPUT strIn;               // error – no length specified BUFFER_INPUT bufIn;               // error – no length specified STRING_OUTPUT strOutArr[10][20];  // error – 2-D arrays not supported STRING str[x];                    // error – variables are not allowed STRING str[myFunc()];             // error – function calls are                                   //         not allowed INTEGER_FUNCTION MyIntFunc( INTEGER x[], INTEGER xArr[][] ) {    xArr[1] = 5;                                         // ok    xArr[1+2] = xArr[3+4];                               // ok    xArr[1+xArr[2]] = xArr[xArr[3]];                     // ok    xArr[MyIntFunc(xArr,x2dArr)] = 6;                    // ok    x2dArr[1][2] = 6;                                    // ok    x2dArr[xArr[1]][xArr[2]] = x2dArr[xArr[5]][xArr[6]]; // ok    Call MyFunc( xArr, x2dArr );                         // ok    xArr = 5;         // error – no index specified    xArr[] = 0;       // error – no index specified    xArr[str] = 6;    // error - s is a STRING    xArr[5][6] = 7;   // error – xArr is not a 2D array    xArr = xArr;      // error – cannot copy arrays    xArr = x2dArr[1]; // error – cannot copy arrays    x2dArr[1] = xArr; // error – cannot copy arrays    Call MyIntFunc( xArr[5], x2dArr ); // error – cannot pass index                                       //         arrays are passed                                       //         by reference } FUNCTION MyStrFunc( STRING s, STRING s[] )   // ok {    STRING sLocal[100];    str = “abc”;                              // ok    strArr[5] = “def”;                        // ok    strIn = s;                                // ok    strOut = s;                               // ok    sInArr[5] = “abc”;                        // ok    sOutArr[5] = “abc”;                       // ok    Call MyStrFunc( str, strArr );            // ok    str[1] = “a”;    // error – s is a string, not an array    sLocal = str[1]; // error – individual characters within                     //         a string can only be accessed                     //         with the function, Byte() } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1302 -------------------------------------------------------------------------------- # Compiler Error 1302 declaration error:  Variable name, ‘\’, exceeds maximum                                       length of \ characters Variable names have a maximum length of 120 characters. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1303 -------------------------------------------------------------------------------- # Compiler Error 1303 declaration error:  Declaration type not allowed within structure: '\'                                  Structure cannot contain String Arrays or Structure                                       variables: '\'                                  Structure definitions not allowed within other structures                                  Local Structure declarations are not allowed Structure datatypes can only be defined globally.  Variables of a defined structure datatype may be declared both globally and locally and passed as function arguments.  INTEGER, LONG_INTEGER, SIGNED_INTEGER, SIGNED_LONG_INTEGER and STRING are the only SIMPL+ datatypes allowed to be used as structure member fields.  INTEGER and LONG_INTEGER can include 1 and 2 dimensional arrays.  String arrays are not permitted. The following are examples of this error: STRUCTURE MyStruct                               // ok {    INTEGER i, i1[10], l2[10][20];                // ok    SIGNED_INTEGER si, si1[10], si2[10][20];      // ok    LONG_INTEGER l, l1[10], l2[10][20];           // ok    SIGNED_LONG_INTEGER sl, sl1[10], sl2[10][20]; // ok    STRING s[100];                                // ok    STRING sArr[10];    // error – string arrays are not allowed                        //         within structures    DIGITAL_INPUT di;   // error – declaration type not allowed    DIGITAL_OUTPUT do;  // error – declaration type not allowed    ANALOG_INPUT ai;    // error – declaration type not allowed    ANALOG_INPUT ao;    // error – declaration type not allowed    STRING_INPUT si;    // error – declaration type not allowed    BUFFER_INPUT bi;    // error – declaration type not allowed    STRING_OUTPUT so;   // error – declaration type not allowed    STRUCTURE locStruct // error – declaration type not allowed    {       INTEGER x;    }    MyStruct ptr;       // error – declaration type not allowed } FUNCTION MyFunc() {    STRUCTURE MyStruct  // error – local structures are not supported    {       INTEGER i, i1[10], l2[10][20];    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1304 -------------------------------------------------------------------------------- # Compiler Error 1304 declaration error:  Local variables must be declared at top of function All local variables within a function block must be declared before any statements are encountered.  Local variables are not allowed to be declared within a block of statements such as inside an if-else or while loop. The following are examples of this error: FUNCTION MyFunc( INTEGER arg1, STRING arg2 ) // ok {    INTEGER i;                  // ok    STRING str[100];            // ok    Print( “Inside MyFunc!” );    INTEGER j;                  // error    if ( i \> 1 )    {       INTEGER k;               // error – if-statement block cannot                                           contain local variables    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1305 -------------------------------------------------------------------------------- # Compiler Error 1305 declaration error:  Local functions not supported A function cannot be defined within another function definition.  All function definitions must be defined with a global scope inside the module. NOTE: Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. The following are examples of this error: FUNCTION MyFunc()          // ok – MyFunc is global {    FUNCTION MyLocalFunc()  // error – MyLocalFunc is local to MyFunc    {    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1306 -------------------------------------------------------------------------------- # Compiler Error 1306 declaration error:  Declaration type can only be used globally: '\' I/O declarations must be defined globally;  they cannot be declared as local variables inside of a function or library file. The following are examples of this error: INTEGER i;               // ok STRING str[100];         // ok DIGITAL_INPUT di;        // ok DIGITAL_OUTPUT do;       // ok ANALOG_INPUT ai;         // ok ANALOG_OUTPUT ao;        // ok STRING_INPUT si[100];    // ok STRING_OUTPUT so;        // ok BUFFER_INPUT bi[100];    // ok FUNCTION MyFunc() {    INTEGER i;            // ok – not an I/O declaration    STRING str[100];      // ok – not an I/O declaration    DIGITAL_INPUT di;     // error    DIGITAL_OUTPUT do;    // error    ANALOG_INPUT ai;      // error    ANALOG_OUTPUT ao;     // error    STRING_INPUT si[100]; // error    STRING_OUTPUT so;     // error    BUFFER_INPUT bi[100]; // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1307 -------------------------------------------------------------------------------- # Compiler Error 1307 declaration error:  Variables must be declared before array                                      declarations: '\' I/O declarations must be declared in a specific order.  All arrays of an I/O declaration type (i.e.: DIGITAL_INPUT) must be declared after any variables of the same type. The following are examples of this error: DIGITAL_INPUT di1, di2;   // ok DIGITAL_INPUT di3;        // ok ANALOG_INPUT ai1          // ok DIGITAL_OUTPUT do1;       // ok ANALOG_INPUT aiArr1[10];  // ok DIGITAL_INPUT di4;        // ok – no DIGITAL_INPUT array exists yet DIGITAL_INPUT diArr1[10]; // ok DIGITAL_OUTPUT do2;       // ok ANALOG_INPUT aiArr2[20];  // ok – multiple arrays are allowed DIGITAL_INPUT di5;        // error – cannot define after diArr1 ANALOG_INPUT ai2;         // error – cannot define after aiArr2 -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1308 -------------------------------------------------------------------------------- # Compiler Error 1308 declaration error:  Declaration cannot be declared in library file: '\' I/O declarations, Parameters and global variables can only be defined in a SIMPL+ module (.usp file).  Libraries files (.usl files) are files that only contain functions.  Local functions variables, function arguments and functions that return values are permitted within library files. The following are examples of this error: ////////////////////////////////////////////////////////////////// //  MyLib.usl INTEGER x;                              // error – x is global STRING str[100];                        // error – str is global DIGITAL_INPUT di;                       // error – di is global INTEGER_PARAMETER intParam;             // error – intParam is                                         //         a Parameter FUNCTION MyFunc() {    INTEGER i, j;                        // ok – i and j are local    STRING str[100];                     // ok – str is local } INTEGER_FUNCTION MyIntFunc( INTEGER x ) // ok – x is local {    INTEGER i, j;                        // ok – i and j are local    STRING str[100];                     // ok – str is local    return (x); } STRING_FUNCTION MyStFunc( STRING s )    // ok – s is local {    INTEGER i, j;                        // ok – i and j are local    STRING str[100];                     // ok – str is local    return (str); } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1309 -------------------------------------------------------------------------------- # Compiler Error 1309 declaration error:  Compiler Directive must be set before all global                                       variable declarations                                  #DEFAULT_NONVOLATILE Compiler Directive already set                                  #DEFAULT_VOLATILE Compiler Directive already set The compiler directives, #DEFAULT_VOLATILE and #DEFAULT_NONVOLATILE, must be used before any global variables are encountered within the SIMPL+ module.  A module cannot contain more than one of these directives. The following are examples of this error: ////////////////////////////////////////////////////////////////// // Example 1 #DEFAULT_VOLATILE     // ok – compiler directive exists before                       //      all global variables INTEGER x; STRING str[100]; DIGITAL_INPUT di; FUNCTION MyFunc() { } ////////////////////////////////////////////////////////////////// // Example 2 INTEGER x; STRING str[100]; DIGITAL_INPUT di; #DEFAULT_VOLATILE     // error – global variables have already been                       //         declared within this module FUNCTION MyFunc() { } ////////////////////////////////////////////////////////////////// // Example 3 #DEFAULT_VOLATILE     // ok – compiler directive exists before                       //      all global variables INTEGER x; STRING str[100]; DIGITAL_INPUT di; #DEFAULT_NONVOLATILE  // error – #DEFAULT_VOLATILE has already                       //         been set INTEGER y; #DEFAULT_NONVOLATILE  // error – #DEFAULT_VOLATILE has already                       //         been set INTEGER z;                       FUNCTION MyFunc() { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1310 -------------------------------------------------------------------------------- # Compiler Error 1310 declaration error:  Compiler directive cannot be in function scope Compiler directives cannot be used locally within functions.  They can only be used at a global level and the directive applies to the entire SIMPL+ module. NOTE: Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. The following are examples of this error: #DEFINE_CONSTANT   MyConst   100         // ok – used globally #USER_LIBRARY “MyUserLib”                // ok – used globally FUNCTION MyFunc() {    #DEFINE_CONSTANT   AnotherConst   100 // error – constants cannot                                          //         be used locally    #USER_LIBRARY “AnotherUserLib”        // error – libraries cannot                                          //         be included locally } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1311 -------------------------------------------------------------------------------- # Compiler Error 1311 declaration error:  Undefined Wait Label: '\'                                  Missing, invalid or already defined Wait label: '\' Wait Statements can be given a label as an optional argument.  This label must be  a unique name and more than one wait statement cannot share the same label name.  The label name can then be used in the Pause, Cancel and Resume wait functions.  All labels must already be declared in within a wait statement before any Pause, Cancel or Resume wait statement can reference it. The following are examples of this error: FUNCTION MyFunc() {    CancelAllWaits();               // ok    CancelWait( MyWaitLabel );      // error – MyWaitLabel has                                    //         not been declared yet    Wait( 500 )                     // ok – Label is not required    {    }    Wait( 500, MyWaitLabel )        // ok – MyWaitLabel is unique    {    }    Wait( 500, MyWaitLabel )        // error – MyWaitLabel has already                                    //         been used    {    }    CancelWait( AnotherWaitLabel ); // error – AnotherWaitLabel has                                    //         not been declared yet    Wait( 500, AnotherWaitLabel )   // ok – AnotherWaitLabel is unique    {    }    CancelWait( AnotherWaitLabel ); // ok    PauseWait( MyWaitLabel );       // ok    ResumeWait( MyFunc );           // error – MyFunc is not a valid                                    //         wait label    ResumeWait( someLabel );        // error – someLabel does not exist } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1312 -------------------------------------------------------------------------------- # Compiler Error 1312 declaration error:  Array boundary exceeded maximum size of ‘num_bytes’ bytes The maximum number of indices for an array is 65535. The following are examples of this error. FUNCTION MyFunc() {    INTEGER int[100], intArr[100][100]; // ok    STRING str[100], strArr[100][100];  // ok    INTEGER int[100000];                // error    INTEGER intArr[100000][100];        // error    INTEGER intArr[100][100000];        // error    STRING str[100000];                 // error    STRING strArr[100000][100];         // error    STRING strArr[100][100000];         // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1313 -------------------------------------------------------------------------------- # Compiler Error 1313 declaration error:  Minimum array size invalid The minimum array size cannot exceed the total size of the array.  The minimum array size must be between 1 and the total size of the array. The following are examples of this error: DIGITAL_INPUT digIn1[10];     // ok DIGITAL_INPUT digIn2[10,5];   // ok – minimum size is 5 ANALOG_INPUT anlgIn3[10,0];   // error – minimum size must be                               //         greater than 0 STRING_INPUT strIn4[10,20];   // error – minimum size of 20 exceeds                               //         total array size of 10 -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1314 -------------------------------------------------------------------------------- # Compiler Error 1314 declaration error:  Minimum array size is not allowed for this                                       datatype: '\'                                    Minimum array size for this datatype has already                                       been declared: '\' Minimum array sizes are only applicable to Input and Output datatypes (i.e.: DIGITAL_INPUT, ANALOG_OUTPUT, STRING_INPUT, etc.).  A variable of another datatype was found trying to define a minimum array size.  Only one array for each Input or Output datatype is allowed to be declared with a minimum array size. The following are examples of this error: DIGITAL_INPUT digIn1[10];    // ok DIGITAL_INPUT digIn2[10,5];  // ok – minimum size is 5 DIGITAL_INPUT digIn3[20,10]; // error – the DIGITAL_INPUT array                              //         variable, digIn2, has already                              //         been declared with a minimum                              //         array size ANALOG_INPUT anlgIn1[10];    // ok ANALOG_INPUT anlgIn2[10,5];  // ok – no other ANALOG_INPUT has been                              //      declared with a minimum array size INTEGER x[10];               // ok INTEGER y[10,5];             // error – INTEGER is not an Input or                              //         Output datatype -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1315 -------------------------------------------------------------------------------- # Compiler Error 1315 construct  error:  Socket receive buffer size missing: '\' The receiving buffer size was not specified within the socket declaration.  All socket declarations must contain a buffer size. The following are examples of this error: TCP_CLIENT tcpClient[1024]; // ok TCP_SERVER tcpServer[1024]; // ok UDP_SOCKET udpSocket[1024]; // ok TCP_CLIENT tcpClient2; // error TCP_SERVER tcpServer2; // error UDP_SOCKET udpSocket2; // error -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1316 -------------------------------------------------------------------------------- # Compiler Error 1316 construct  error:  Invalid Parameter Type: '\'.  Expected Types: 'Decimal',                                  'Time', 'HexAddress', 'Percent', 'Constant'                                  String Parameters cannot contain a type: '\' An invalid Parameter Type was specified within a parameter declaration.  Parameter Types are optional when declaring parameter data types and can only be one of the following types:  ‘Decimal’, ‘Time’, ‘HexAddress’, ‘Percent’ or ‘Constant’.  String parameters cannot contain a parameter type. The following are examples of this error: INTEGER_PARAMETER intParam; // ok INTEGER_PARAMETER intParam:Decimal; // ok INTEGER_PARAMETER intParam:String; // error – String is not a valid parameter type LONG_INTEGER_PARAMETER longIntParam:Time; // ok SIGNED_INTEGER_PARAMETER signedIntParam; // ok SIGNED_LONG_INTEGER_PARAMETER signedLongIntParam; // ok STRING_PARAMETER strParam; // ok STRING_PARAMETER strParam:Time; // error – STRING_PARAMETERS cannot // contain a paramter type STRING_PARAMETER strParam:String; // error – String is not a valid // parameter type -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1317 -------------------------------------------------------------------------------- # Compiler Error 1317 construct  error:  Declaration cannot be declared as Nonvolatile: '\' A variable was found trying to be declared with the NONVOLATILE keyword. The following are examples of this error: NONVOLATILE DIGITAL_INPUT di; // error NONVOLATILE TCP_CLIENT tcpClient[1024]; // error NONVOLATILE TCP_SERVER tcpServer[1024]; // error NONVOLATILE INTEGER i; // ok NONVOLATILE INTEGER str[10]; // ok VOLATILE UDP_SOCKET udpSocket[1024]; // ok – VOLATILE is the                                               //      default type VOLATILE DIGITAL_INPUT di; // ok -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1318 -------------------------------------------------------------------------------- # Compiler Error 1318 construct  error:     Invalid Parameter Property Value or Property Value not allowed for \ Invalid Parameter Property Value (Numeric value expected) Invalid Parameter Property Value (String expected) A parameter was being assigned a value that was either out of range or of the wrong type for the parameter specified.  Numeric values can only be assigned to non-String_Parameters with propValidUnits containing one of the following types:  unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks.  String values can only be assigned to a String_Parameter and with propValidUnits=unitString. The following are examples of this error: INTEGER_PARAMETER intParam; STRING_PARAMETER strParam; #BEGIN_PARAMETER_PROPERTIES intParam    specified    propValidUnits = unitDecimal; // ok    propValidUnits = unitString; // error – intParam is not                                            a string    propDefaultValue = “abc”; // error – number expected    propDefaultValue = 5d; // ok #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES strParam        propValidUnits = unitDecimal; // error – strParam is not                                             a number    propValidUnits = unitString; // ok    propDefaultValue = “abc”; // ok    propDefaultValue = 5d; // error #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1319 -------------------------------------------------------------------------------- # Compiler Error 1319 construct  error:     Invalid format specifier: \,  propValidUnits undefined or specifier not declared within propValidUnits Specifier not declared within propValidUnits A parameter was being assigned a value that was either out of range or of the wrong type.  Before any property or property value can be defined, propValidUnits must be specified.  The PropDefaultUnit specified must be contained within propValidUnits. The following are examples of this error: INTEGER_PARAMETER intParam; #BEGIN_PARAMETER_PROPERTIES intParam    propBounds = 25d, 50d;  // error – propValidUnits undefined #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES intParam    propValidUnits = unitDecimal;    propBounds = 25d, 50d;  //ok – propValidUnits defined above #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES intParam    propValidUnits = unitDecimal|unitCharacter;    propDefaultUnit = unitHex; // error – unitHex not contained                                          within propValidUnits    propDefaultUnit = unitCharacter; // ok    propBounds = 25d, 50d;  // ok – valid Integer range is 0-65535    propBounds = -50d, -25d;  // error – Integer range is not 0-65535    propBounds = “abc”, "def"; // error – “abc” is not a valid number #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1320 -------------------------------------------------------------------------------- # Compiler Error 1320 construct  error:  Cannot combine property unit: \ The property unit, unitString, cannot be combined with any other property unit (i.e., unitDecimal,unitCharacter, etc). The following are examples of this error: INTEGER_PARAMETER intParam; STRING_PARAMETER strParam; #BEGIN_PARAMETER_PROPERTIES intParam    propValidUnits = unitDecimal|unitCharacter; // ok    propValidUnits = unitString; // ok    propValidUnits = unitString|unitDecimal; // error #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1321 -------------------------------------------------------------------------------- # Compiler Error 1321 construct  error:  Dynamic variable declarations cannot be used with the    #DEFAULT_NONVOLATILE compiler directive The declaration keyword, Dynamic, can only be used when #DEFAULT_VOLATILE is specified for the program module. The following are examples of this error: // MODULE A #DEFAULT_NONVOLATILE dynamic integer intArr[10]; // error // MODULE B dynamic integer intArr[10]; // error – #DEFAULT_NONVOLATILE is the    default state for this module // MODULE C #DEFAULT_VOLATILE dynamic integer intArr[10]; // ok -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1322 -------------------------------------------------------------------------------- # Compiler Error 1322 construct  error:  Variable cannot be declared as dynamic: \ The declaration keyword, Dynamic, can only be used with string or array declarations.  I/O declarations are not allowed to be declared as dynamic. The following are examples of this error: #DEFAULT_VOLATILE dynamic integer i; // error – ‘i’ is not an array dynamic string_input si // error – I/O declarations are not permitted dynamic integer intArr[10]; // ok dynamic string str[10]; // ok -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1323 -------------------------------------------------------------------------------- # Compiler Error 1323 construct  error: #ENABLE_DYNAMIC compiler directive must be used when                                     using declaring variables dynamically In order to declare Strings and Arrays dynamically, the compiler directive, #ENABLE_DYNAMIC, must be specified beforehand within the module. Dynamic memory allocation is the allocation of a variable’s memory at run-time.  The amount of memory allocated is determined by the program at the time of allocation and need not be known in advance. Using Dynamic variables allows a String or Array variable’s memory allocation to grow or shrink in size.  Rather than initially declare a String or Array variable to some large amount, the variable can be dynamically resized to the correct amount in real-time. NOTE:  Dynamic variables are specific to Firmware versions 4.000 and later The following are examples of this error: / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // Example 1 #ENABLE_DYNAMIC DYNAMIC STRING str[10]; // ok, #ENABLE_DYNAMIC                         // declared at top of module FUNCTION foo() {    SIGNED_INTEGER status;    DYNAMIC INTEGER arr[10][10]; // ok, #ENABLE_DYNAMIC                                 // declared at top of module    status = ResizeString( str, 100 );    status = ResizeArray( arr, 200, 100); } ////////////////////////////////////////////////////////////////////////// // Example 2 DYNAMIC STRING str[10]; // error, #ENABLE_DYNAMIC not                         // declared at top of module FUNCTION foo() {    SIGNED_INTEGER status;    DYNAMIC INTEGER arr[10][10]; // error, #ENABLE_DYNAMIC not                                 // declared at top of module    status = ResizeString( str, 100 );    status = ResizeArray( arr, 200, 100); } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1324 -------------------------------------------------------------------------------- # Compiler Error 1324 declaration error: propList cannot be used in conjunction with propBounds.                                   propBounds cannot be used in conjunction with propList. NOTE: propList and propBounds cannot be used within the same parameter properties block. The following are examples of this error: INTEGER_PARAMETER iParam, iAnotherParam; #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propBounds = 10,20; // ok    propList = {10d, "value1"}, {20d, "value2" }; // error -                                  // propBounds previously used                                  // within block #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propList = {10d, "value1"}, {20d, "value2" }; // ok    propBounds = 10,20; // error -                        // propList previously used                        // within block #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propList = {10d, "value1"}, {20d, "value2" }; // ok #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propBounds = 10,20; // ok #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1325 -------------------------------------------------------------------------------- # Compiler Error 1325 declaration error: propDefaultValue must be declared before using propList.                                propBounds must be declared before using propDefaultValue.                                propList must contain an element with the propDefaultValue. Default values, if specified, must be specified before a propList declaration.  If using propBounds, the Default Value must be defined beforehand.  If a default value is specified, the propList must contain at least one element that contains this default value. The following are examples of this error: INTEGER_PARAMETER iParam, iAnotherParam; #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propBounds = 10d,20d; // ok    propList = {10d, "value1"}, {20d, "value2" }; // error -                                  // propBounds previously used                                  // within block #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultValue = 15d; // ok    propBounds = 10d,20d; // ok #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultValue = 15d;// ok    propBounds = 10d,20d; // error – propDefaultValue has been                          // defined beforehand #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultValue = 15d;// ok    propList = {10d, "value1"}, {20d, "value2" }; // error –                           // propDefaultValue has been                           // defined beforehand #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1326 -------------------------------------------------------------------------------- # Compiler Error 1326 declaration error: propDefaultValue is not within propBounds.                                   propBound's Upper Bound value must be greater than the                                   Lower Bound value                                   propBound's Lower, Upper and Default values must be of the same                                   type The Default Value must be within the bounds specified in propBounds.  The compiler will also enforce that the lower bound is less than the upper bound.  All values specified must also be of the type indicated within propValidUnits. The following are examples of this error: INTEGER_PARAMETER iParam, iAnotherParam; #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultUnit = unitDecimal;    propBounds = 1d,20d; // ok, 1d and 20d are both of type                         // unitDecimal.    propDefaultValue = 10d;// ok, 10d is within 1d and 20d and                           // of type unitDecimal. #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultUnit = unitDecimal;    propBounds = 1d,20d;    propDefaultValue = 50d; // error, 50d is NOT within 1d and 20d #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propDefaultUnit = unitDecimal;    propBounds = 50d,20d; // error – 50d is not less than 20d #END_PARAMETER_PROPERTIES #BEGIN_PARAMETER_PROPERTIES iParam, iAnotherParam        propValidUnits = unitDecimal;    propBounds = 50t,20t; // error – 50t is not of type unitDecimal #END_PARAMETER_PROPERTIES -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1327 -------------------------------------------------------------------------------- # Compiler Error 1327 dconstruct  error: Nonvolatile variables cannot be resized:  \ Variables that are declared as volatile are only allowed to be resized.  Either the global compiler directive, #VOLATILE, or the declaration modifier, “VOLATILE”, may be used to declare a variable as volatile. The following are examples of this error: #DEFAULT_NONVOLATILE integer intArr[10]; nonvolatile int2dArr[10][20]; nonvolatile string str[100]; volatile myIntArr[10]; volatile myStr[100]; function MyFunc() {    ResizeArray( intArr, 100 );  // error – intArr is declared as nonvolatile by default;    ResizeArray( int2dArr, 15, 25 );  // error – int2dArr is nonvolatile    ResizeString( str, 200 ); // error – str is nonvolatile    ResizeArray( myIntArr, 20 ); // ok – myIntArr is volatile    ResizeString( myStr, 200 ); // ok – myStr is volatile } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1328 -------------------------------------------------------------------------------- # Compiler Error 1328 declaration  error: Encoding Types are only valid for STRING declarations Encoding only applies to strings.  The declaration modifiers, ASCII, UTF16 and INHERIT can only be used with variables of type STRING. The following are examples of this error: ASCII string str[100]; // ok – str is of type ‘string’ UTF16 integer myIntArr[10]; // error – myIntArr is of type ‘integer’ INHERIT string myStr[100]; // ok – myStr is of type ‘string’ -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1329 -------------------------------------------------------------------------------- # Compiler Error 1329 **declaration error:   Class name exists in one or more namespaces. ** **                                     Fully-qualified name must be specified: ‘\’** SIMPL# Libraries can contain multiple namespaces, each of which can contain one or more classes. Class names do not have to be unique when used in different namespaces. For example, namespaceA and namespaceB can each contain a class named, ‘MyClass’. Using the example above, if SIMPL+ were to declare a variable of type, ‘MyClass’, the compiler would not know which namespace to use and would result in an ambiguous declaration. For SIMPL+ to resolve this error, the fully-qualified name must be specified. Fully-qualified names are represented by specifying both the namespace and class name, using the dot-notation to separate them. The SIMPL+ declaration would be: ‘namespaceA.MyClass \’. The following are examples of this error: SIMPL# Library // SimplSharpLibrary.clz namespace MyNamespace1 {    public class MyClass    {         public int intVar();    } } namespace MyNamespace2 {    public class MyClass    {         public int intVar();    } } SPlusModule.usp // UserModule.usp #USER_SIMPLSHARP_LIBRARY "SimplSharpLibrary" MyClass class1;               // error – compiler doesn’t know                                  whether MyClass is from                                  MyNamespace1 or MyNamespace2 MyNamespace1.MyClass class1;  // ok – fully-qualified name is used MyNamespace2.MyClass class2;  // ok – fully-qualified name is used FUNCTION MyFunc() {    Class1.intVar = 1;      // ok – use SIMPL+ variable as normal } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1400 -------------------------------------------------------------------------------- # Compiler Error 1400 assignment error:  Illegal Assignment Assignments in SIMPL+ require that the value being assigned to a variable must equate to the same type as that variable.  Integer variables can only be assigned integer values and string variables can only be assigned a string value. - If a complex assignment is being made, make sure that all parenthesis are matched.  In other words, all opening parenthesis must have a matching closing parenthesis. - When comparing 2 strings (‘=’, ‘\<’, ‘\>=’, etc.), the resulting value is an integer - Input variables (DIGITAL_INPUT, ANALOG_INPUT, STRING_INPUT and BUFFER_INPUT) cannot be assigned a value. The following are examples of this error: INTEGER x, y; STRING str[100], str2[100]; DIGITAL_INPUT digIn; DIGITAL_OUTPUT digOut; ANALOG_OUTPUT anlgOut; FUNCTION MyFunc() {    str = “abc”;                // ok    str = “abc” + “def”;        // ok    str = str2;                 // ok    x = 1;                      // ok    x = digOut;                 // ok    x = (str = str2);           // ok    x = 5 \* (1 + (str \> str2)); // ok    digOut = x;                 // ok    digOut = 5;                 // ok    digOut = anlgIn;            // ok – both are integer types    x = str;                    // error – str does not equate to                                //         an integer                                //         atoi() should be used    digIn = 1;                  // error - digIn is an input variable    str = 5;                    // error – 5 is an integer                                //         MakeString() should be used    str = str2 = “abc”;         // error = str2 = “abc” is an equality                                //         test, not an assignment } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1401 -------------------------------------------------------------------------------- # Compiler Error 1401 assignment error:  Variable cannot be used for assignment:  '\' Function arguments that have been declared as ReadOnlyByRef can only have their values read;  values cannot be assigned to them.   The following are examples of this error: FUNCTION MyFunc( INTEGER x, ReadOnlyByRef INTEGER y ) {    x = 5; // ok    x = y; // ok – the value of y can be read    y = 6; // error – y is read-only } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1402 -------------------------------------------------------------------------------- # Compiler Error 1402 assignment error:  Variable can only be used for assignment: '\' STRING_OUTPUT variables can only have their values read.  Once assigned a value, that value is immediately acted upon by the control system, and the value is assumed to be unknown thereafter. The following are examples of this error: STRING_OUTPUT sOut; STRING str[100]; FUNCTION MyFunc() {    str = “abc”;                // ok    sOut = str;                 // ok – sOut can be assigned a value    sOut = “abc”;               // ok – sOut can be assigned a value    str = sOut;                 // error – the value of sOut is lost    Print( “str = %s”, str );   // ok – STRINGs can be read and written    Print( “sOut = %s”, sOut ); // error – the value of sOut is unknown } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1500 -------------------------------------------------------------------------------- # Compiler Error 1500 function argument error: Argument \ cannot be passed by reference A variable was being passed that can either only have a value assigned to it, or it’s value be copied into another variable or used within an expression.  An example of this is trying to pass a STRING_INPUT variable as a function argument; the STRING_INPUT must first be copied into a STRING variable and then passed. Pass by Reference – The function will act directly on the variable that was passed as the argument.  Any changes to the variable within the called function the will be reflected within the calling function. Pass by Value – The function creates a local copy of the source variable.  Any changes to this local copy are not reflected in the source variable that was originally passed to the function.  The source variable will still retains its original value from before the function was called. The following are examples of this error: INTEGER i; STRING str[100]; STRING_INPUT strIn[100]; STRING_OUTPUT strOut; DIGITAL_INPUT di; FUNCTION MyFunc( STRING s ) {    str = strIn;    Call MyFunc( str );      // ok – the previous statement copied                             //      ‘strIn’ into ‘str’    Call MyFunc( “abc” );    // ok    Call MyFunc( strIn );    // error – strIn is a STRING_INPUT and                             //         cannot be passed by reference    Call MyFunc( strOut );   // error – strIn is a STRING_OUTPUT and                             //         cannot be passed by reference } FUNCTION MyFunc2( ByRef STRING s ) // error – STRINGs cannot be                                    //         passed by reference {    Call MyFunc2( str );            // error – STRINGs cannot be                                    //         passed by reference } FUNCTION AnotherFunc( ByRef INTEGER x ) {    Call AnotherFunc( 1 );   // ok    Call AnotherFunc( di );  // error – di is a DIGITAL_INPUT and                             //         cannot be passed                             //         by reference } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1501 -------------------------------------------------------------------------------- # Compiler Error 1501 function argument error: Argument \ cannot be passed by value In SIMPL+, arrays can only be passed by reference.  The keyword, ByVal, cannot be used within a function’s argument list in conjunction with arrays.  A copy of an individual element within an array must first be copied into an INTEGER or STRING variable and then that variable can be passed. Pass by Reference – The function will act directly on the variable that was passed as the argument.  Any changes to the variable within the called function the will be reflected within the calling function. Pass by Value – The function creates a local copy of the source variable.  Any changes to this local copy are not reflected in the source variable that was originally passed to the function.  The source variable will still retains it’s original value from before the function was called. The following are examples of this error: FUNCTION MyFunc( ByVal INTEGER intArr[] )   // error – arrays cannot be                                             //         passed by value { } FUNCTION MyFunc( ByVal STRING strArr[] )    // error – arrays cannot be                                             //         passed by value { } FUNCTION MyFunc( ByVal INTEGER intArr[][] ) // error – arrays cannot be                                             //         passed by value { } FUNCTION MyFunc( ByVal STRING strArr[][] )  // error – arrays cannot be                                             //         passed by value { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1502 -------------------------------------------------------------------------------- # Compiler Error 1502 function argument error:  Function contains incomplete number of arguments                                                  Function call contains an unmatched number of                                                   arguments When calling a function that contains parameter lists, the number of arguments passed to the function must match the number of parameters defined for that function. The following are examples of this error: FUNCTION MyFunc( INTEGER x, STRING str ) {    Call MyFunc( 1, “abc” ); // ok    Call MyFunc();           // error – 2 arguments are expected    Call MyFunc( 1 );        // error – argument 2 is missing } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1503 -------------------------------------------------------------------------------- # Compiler Error 1503 function argument error:  Input or Output signal expected:  '\' The expected identifier must be of an Input or Output signal datatype (i.e.:  DIGITAL_INPUT, ANALOG_OUTPUT, STRING_INPUT, etc.). The following are examples of this error: DIGITAL_INPUT digIn, digInArr[10]; DIGITAL_INPUT digIn; ANALOG_INPUT anlgIn; ANALOG_OUTPUT anlgOut; STRING_INPUT strIn[100]; STRING_OUTPUT strOut; BUFFER_INPUT buffIn[100]; INTEGER i; STRING str[100]; FUNCTION MyFunc() {    i = IsSignalDefined( digIn );       // ok    i = IsSignalDefined( digInArr[5] ); // ok    i = IsSignalDefined( digOut );      // ok    i = IsSignalDefined( anlgIn );      // ok    i = IsSignalDefined( anlgOut );     // ok    i = IsSignalDefined( strIn );       // ok    i = IsSignalDefined( strOut );      // ok    i = IsSignalDefined( buffIn );      // ok    digOut = IsSignalDefined( i );      // error – ‘i’ is not an Input                                        //         or Output signal    i = IsSignalDefined( str );         // error – ‘i’ is not an Input                                        //         or Output signal    digOut = IsSignalDefined( 5 );      // error – ‘5’ is not an Input                                        //         or Output signal } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1504 -------------------------------------------------------------------------------- # Compiler Error 1504 function argument error:  Incomplete number of format string arguments                                                  Format string contains an unmatched number                                                      of arguments                                                  Argument \ is missing or invalid.                                                      Format Specifier expected                                                   Argument \ is missing or invalid.                                                      \ expected Format lists contain format specifiers that tell the compiler to replace a given specifier with the value or result given in the argument list that follows.  A format list is analogous to a function parameter list in that the format specifier tells the compiler what type of argument to expect.  For each format specifier, their must be a corresponding value or result in the argument list that follows.  This value or result must also be of the same datatype. NOTE: Format strings contain specifications that determine the output format for the arguments.  The format argument consists of ordinary characters, escape sequences, and (if arguments follow format) format specifications  Format Specifications always begin with a percent sign (%) and are read left to right. When the first format specification is encountered (if any), it converts the value of the first argument after format and outputs it accordingly. The second format specification causes the second argument to be converted and output, and so on. The following are examples of this error: FUNCTION MyFunc() {    INTEGER x, intArr[100];    STRING str[100], strArr[100][100];    Print( “Hello World” );                                    // ok    Print( “My name is %s.  My age is %d”, “David”, 33 );      // ok    Print( “My name is %s.  My age is %d”, str, x );           // ok    MakeString( str, “Hello World” );                          // ok    MakeString( str, “My name is %s.  My age is %d”, str, x ); // ok    Print( “My name is %s.  My age is %d”, “David” );     // error –                         // %d format specifier does not have a                         // corresponding value    Print( “My name is %s.  My age is %d”, 33, “David” ); // error -                         // both format specifiers contain corresponding                         // values of different datatypes    SetArray( strArr, 1 );     // ok    SetArray( strArr, “abc” ); // ok    SetArray( intArr, 0 );     // ok    SetArray( “abc”, 1 );      // error – “abc” is not an array    SetArray( 1, “abc” );      // error – 1 is not an array } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1505 -------------------------------------------------------------------------------- # Compiler Error 1505 function argument error:  Format string contains invalid format specifier An invalid format specifier was used within a format string. Format strings contain specifications that determine the output format for the arguments.  The format argument consists of ordinary characters, escape sequences, and (if arguments follow format) format specifications  Format Specifications always begin with a percent sign (%) and are read left to right. When the first format specification is encountered (if any), it converts the value of the first argument after format and outputs it accordingly. The second format specification causes the second argument to be converted and output, and so on. The following are examples of this error: FUNCTION MyFunc() {    Print( “Hello World” );                                    // ok    Print( “My name is %s.  My age is %d”, “David”, 33 );      // ok    Print( “My name is %xs”, “David” ); // error - %xs is an invalid                                        //         format specifier } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1506 -------------------------------------------------------------------------------- # Compiler Error 1506 function argument error:  0, 1 or 2 constant expected for argument 1 The function, MakeString, can contain a 0, 1, 2 as the first argument.  This tells the control system to output the resulting string to a specific destination.  An integer value other than 0, 1 or 2 was encountered as the first argument of MakeString(). The different destinations are as follows:    0:  Computer Port, same as PRINT.    1:  CPU (same functionality as the SendPacketToCPU function)    2:  Cresnet Network (same functionality as the SendCresnetPacket function). The following are examples of this error: FUNCTION MyFunc( INTEGER x, STRING str ) {    Call MyFunc( 1, “abc” ); // ok    Call MyFunc();           // error – 2 arguments are expected    Call MyFunc( 1 );        // error – argument 2 is missing } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1507 -------------------------------------------------------------------------------- # Compiler Error 1507 function argument error:  Argument \:  Missing or invalid array An integer or string variable array was expected and was not encountered. The following are examples of this error: FUNCTION MyFunc( INTEGER x[], STRING str[] ) {    INTEGER i;    STRING strArr[100][100];    SetArray( x, 1 );         // ok    Call MyFunc( x, StrArr ); // ok    SetArray( i, 1 );         // error – i is not an array    Call MyFunc( 1, “abc” );  // error – 1 is not an array } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1508 -------------------------------------------------------------------------------- # Compiler Error 1508 function argument error:  Variable cannot be passed to read file functions: '%1':                                                 '\' Read file functions (ReadInteger, ReadString, etc.) can only contain variables that can be written to for the function’s resulting read buffer. The following are examples of this error: DIGITAL_OUTPUT digOut; STRING_OUTPUT strOut; INTEGER_PARAMETER intParam; FUNCTION MyFunc( SIGNED_INTEGER nHandle ) {    STRING str[100];    INTEGER x;    ReadInteger( nHandle, x );      // ok    ReadString( nHandle, str );     // ok    ReadInteger( nHandle, digOut ); // error    ReadString( nHandle, strOut );  // error    ReadString( nHandle, intParam );  // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1509 -------------------------------------------------------------------------------- # Compiler Error 1509 **function argument error: Class variable name expected: '\'** A valid class name was expected for a function argument and was not found. The following are examples of this error: MyClass class1;  // MyClass is defined within a SIMPL# Library // ok – class1 is defined RegisterEvent( class1, mySimplSharpEvent, mySPlusEventHandler ); // error – someclass is not defined RegisterDelegate( someclass, myDelegateProp, myDelegateCallbackFn ); // error – only valid variables are allowed RegisterEvent( “event”, mySimplSharpEvent, mySPlusEventHandler ); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1510 -------------------------------------------------------------------------------- # Compiler Error 1510 **function argument error: Class event handler expected: '\'** **A** valid class event handler was expected for a function argument and was not found. The following are examples of this error: MyClass class1;  // MyClass is defined within a SIMPL# Library // ok – class1 is defined RegisterEvent( class1, mySimplSharpEvent, mySPlusEventHandler ); // error – someSimplSharpEvent is not defined within SIMPL# Library RegisterEvent( class1, someSimplSharpEvent, mySPlusEventHandler); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1600 -------------------------------------------------------------------------------- # Compiler Error 1600 construct  error:  'Function Main' cannot contain function parameters                                'Function Main' cannot return a value Function Main is the starting point of a SIMPL+ program.  It is automatically called once when the system startup or is reset.  Since this function is invoked by a method outside of the SIMPL+ module, no arguments can be included in it’s argument list and no value can be returned from it. The following are examples of this error: Function Main()                     // ok { } INTEGER_FUNCTION Main()             // error – Main() cannot return                                     //         a value { } Function Main( INTEGER cmdLineArg ) // error – Main() cannot contain                                     //         a parameter list { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1601 -------------------------------------------------------------------------------- # Compiler Error 1601 construct  error:  Duplicate CASE Statement                                 Constant expected: '\' Unlike the Switch Statement the CSwitch statement’s case statements must consist of unique values.  Expressions are not permitted within the case statements.  Instead, each case statement must contain a unique integer value for the CSwitch’s comparison. The following are examples of this error: FUNCTION MyFunc( INTEGER x ) {    STRING str[100];    CSwitch( x )    {       case (1):     // ok – 1 has not been used yet       {       }       case (2):     // ok – 2 has not been used yet       {       }       case (2):     // error – 2 has been previously used       {       }       case (5+6):   // error – expressions are not allowed       {       }       case (x):     // error – variables are not allowed       {       }       case (“abc”): // error – strings are not allowed       {       }       case (str):   // error – strings are not allowed       {       }    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1602 -------------------------------------------------------------------------------- # Compiler Error 1602 construct  error:  Switch statement contains 'default' without 'case' labels The Switch and CSwitch constructs must contain ‘case’ statements if the ‘default’ statement is to be used.  The ‘default’ statement is optional. The following are examples of this error: FUNCTION MyFunc( INTEGER x ) {    Switch ( x )    {       case (1):  // ok       {       }       default:   // ok       {       }    }    CSwitch ( x )    {       case (1):  // ok       {       }       default:   // ok       {       }    }    Switch ( x )    {       default:   // error – no Case statement in Switch       {       }    }    CSwitch ( x )    {       default:   // error – no Case statement in Switch       {       }    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1603 -------------------------------------------------------------------------------- # Compiler Error 1603 construct  error:  #CATEGORY does not exist: '\'.                                    Defaulting to Category Type, ""32"" (Miscellaneous). The category number for this compiler directive was not found or was not a valid category number within the Symbol Tree Category List within SIMPL.  The category number must be enclosed in quotation marks. Selecting Edit | Insert Category from the SIMPL+ menu will display the list of valid category numbers and give the option for this compiler directive to be automatically inserted into the SIMPL+ module. The following are examples of this error: #CATEGORY “6”                 // ok – “6” is the category number                               //       for Lighting #CATEGORY “Lighting”          // error – the category number, “6”,                               //         should be used instead of                               //         the category symbol name #CATEGORY 6                   // error – the category number should                               //         be enclosed in quotation marks #CATEGORY 99                  // error – invalid category number #DEFINE_CONSTANT MyCategory 6 #CATEGORY MyCategory          // error – cannot substitute category                               //         number with #DEFINE_CONSTANTs -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1604 -------------------------------------------------------------------------------- # Compiler Error 1604 construct  error:  'EVENT' already has a body The EVENT statement can only be defined once per SIMPL+ module.  A previously defined definition of EVENT was already encountered by the compiler. The following are examples of this error: EVENT  // ok { } EVENT  // error – EVENT is already defined { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1605 -------------------------------------------------------------------------------- # Compiler Error 1605 construct  error:  Function can only be contained within an event The function, TerminateEvent, can only be used within a PUSH, CHANGE, RELEASE or EVENT statement.  The compiler encountered this function outside of one of these event functions. The following are examples of this error: DIGITAL_INPUT digIn; EVENT {    TerminateEvent;    // ok } PUSH digIn {    TerminateEvent;    // ok } RELEASE digIn {    TerminateEvent;    // ok } CHANGE digIn {    TerminateEvent;    // ok } FUNCTION MyFunc() {    while (1)    {       TerminateEvent; // error – TerminateEvent is not within                       //         an event function    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1606 -------------------------------------------------------------------------------- # Compiler Error 1606 construct  error:  Statement must be contained within a loop statement The ‘break’ and 'continue' statements can only be used with a loop construct.  Valid loop constructs are While loops, Do-While loops and For loops.  The compiler encountered this function outside of one of these event functions. The following are examples of this error: FUNCTION MyFunc() {    INTEGER I;    for ( i = 1 t 10 )    {       break;    // ok    }    while (1)    {       continue;    // ok    }    do    {       break;    // ok    } until (1);    if (1)    {       break;    // error – break cannot exist within an ‘if’ statement    } } EVENT {    break;       // error – TerminateEvent should be used instead } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1607 -------------------------------------------------------------------------------- # Compiler Error 1607 construct  error:  GetLastModifiedArrayIndex may return an ambiguous                                    signal index If an event function (EVENT, PUSH, CHANGE, RELEASE) is acting on more than one input array signal, the specific array will not be able to be determined based on the index returned from GetLastModifiedArrayIndex().  In order to use GetLastModifiedArrayIndex() for multiple input signal arrays, a separate event function will have to be defined for each array. The following are examples of this error: DIGITAL_INPUT digIn[10]; ANALOG_INPUT anlgIn[10]; PUSH digIn {    INTEGER i;    i = GetLastModifiedArrayIndex();  // ok – index from digIn } PUSH anlgIn {    INTEGER i;    i = GetLastModifiedArrayIndex();  // ok – index from anlgIn } CHANGE digIn, anlgIn {    INTEGER i;    i =  GetLastModifiedArrayIndex(); // error – ambiguous result } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1608 -------------------------------------------------------------------------------- # Compiler Error 1608 construct  error:  Missing library file name A filename was not found following the compiler directive, #USER_LIBRARY or #CRESTRON_LIBRARY.  This filename must be enclosed within quotation marks.  The file extension (.usl or .csl) should NOT be used when specifying the filename. The following are examples of this error: #USER_LIBRARY “MyUserLib”     // ok #CRESTRON_LIBRARY “EvntSched” // ok #USER_LIBRARY MyUserLib       // error – missing quotation marks #USER_LIBRARY MyUserLib.usl   // error – missing quotation marks and                               //         extension is not allowed -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1609 -------------------------------------------------------------------------------- # Compiler Error 1609 construct  error:  Function can only be contained within Function Main The function can only be used within the Function Main.  The compiler encountered this function call outside of this function The following are examples of this error: DIGITAL_INPUT digIn; PUSH digIn {    WaitForInitializationComplete();    // error – not in Function Main } FUNCTION MyFunc() {    WaitForInitializationComplete();    // error – not in Function Main } FUNCTION MyFunc() {    if( WaitForInitializationComplete() \< 0 )    // ok    {       print(Error waiting for initialization complete\n");       return;    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1610 -------------------------------------------------------------------------------- # Compiler Error 1610 construct error: GetLastModifiedArrayIndex cannot be used within a Wait Statement The compiler encountered this function call within a Wait Statement. The following are examples of this error: ANALOG_INPUT AnlgIn; INTEGER i; CHANGE AnlgIn {    i = GetLastModifiedArrayIndex();    // ok } CHANGE AnlgIn {    Wait( 100 )       i = GetLastModifiedArrayIndex();    // error } CHANGE AnlgIn {    Wait( 100 )    {       i = GetLastModifiedArrayIndex();    // error    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1611 -------------------------------------------------------------------------------- # Compiler Error 1611 construct  error:  Invalid Structure type.  Expected Structure(s): '\' An invalid structure type was encountered within a construct. The following are examples of this error: ANALOG_INPUT AnlgIn; TCP_CLIENT tcpClient[1024]; TCP_SERVER tcpServer[1024]; UDP_SOCKET udpSocket[1024]; CONNECT tcpClient // ok { } DISCONNECT tcpServer // ok { } RECEIVE udpSocket // ok { } CONNECT AnlgIn // error – AnlgIn is not a socket type { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1612 -------------------------------------------------------------------------------- # Compiler Error 1612 construct  error:  Category Name can only be assigned to custom category #46.  Category #\ found" Custom category names can only be assigned to category “46”.   A different category number was found. The following are examples of this error: #CATEGORY “46” “My Custom Category”// ok – “46” is the custom category number #CATEGORY 6 “My Custom Category”// error – 6 is not the custom                                    category number -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1613 -------------------------------------------------------------------------------- # Compiler Error 1613 construct  error:  SocketGetSenderIPAddress can only be used with a SOCKETRECEIVE event. SocketGetSenderIPAddress can only be used within the SOCKETRECEIVE event.  It cannot be used inside any other declared function or event type. The following are examples of this error: SOCKETRECEIVE MyUDP {     SIGNED_INTEGER Status;     STRING IPAddress[32];     Status = SocketGetSenderIPAddress(MyUDP, IPAddress ); // ok } SOCKETDISCONNECT MyUDP {     SIGNED_INTEGER Status;     STRING IPAddress[32];     Status = SocketGetSenderIPAddress(MyUDP, IPAddress ); // error } Function MyFunc() {     SIGNED_INTEGER Status;     STRING IPAddress[32];     Status = SocketGetSenderIPAddress(MyUDP, IPAddress ); // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1614 -------------------------------------------------------------------------------- # Compiler Error 1614 construct  error:  SocketGetStatus can only be used with a SOCKETSTATUS event. SocketGetStatus can only be used within the SOCKETSTATUS event.  It cannot be used inside any other declared function or event type. The following are examples of this error: SOCKETSTATUS MyServer {     SIGNED_INTEGER Status;     Status = SocketGetStatus(); // ok } SOCKETRECEIVE MyServer {     SIGNED_INTEGER Status;     Status = SocketGetStatus(); // error } Function MyFunc() {     SIGNED_INTEGER Status;     Status = SocketGetStatus(); // error } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1615 -------------------------------------------------------------------------------- # Compiler Error 1615 construct  error:  GetExceptionMessage/GetExceptionCode can only be used within a CATCH statement block The functions, GetExcpetionMessage and GetExceptionCode can only be used within the CATCH portion of a TRY-CATCH statement block.  It cannot be used inside any other type of statement block or event handler. The following are examples of this error: Function MyFunc() {    string str[100];    integer result;    TRY    {       // some code…    }    CATCH    {       str = GetExceptionMessage(); // ok – GetExceptionMessage is within the CATCH block.    }    result = GetExceptionCode();  // error – GetExceptionCode is outside of the CATCH block. } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1616 -------------------------------------------------------------------------------- # Compiler Error 1616 **construct error:Callback function missing or has an unmatched argument list:** **                                 ‘\’** When registering delegates, the callback function specified must be valid and exist within the SIMPL+ module. The delegate callback function’s signature must match the signature within the SIMPL# Library. The following are examples of this error: // SimplSharpLibrary.clz public delegate int DelegateIntFn(int value); SPlusModule.usp // UserModule.usp #USER_SIMPLSHARP_LIBRARY "SimplSharpLibrary" MyClass class1;  // MyClass is defined within a SIMPL# Library callback signed_long_integer_function MyIntDelegateCallbackFn(                              signed_long_integer value ) callback string_function MyStringDelegateCallbackFn() {    return (0); } // ok – MyIntDelegateCallbackFn is defined and has a matching signature RegisterDelegate( class1, myDelegateFn, MyIntDelegateCallbackFn); // error – MyStringDelegateCallbackFn is defined, but does not have a            matching signature RegisterDelegate( class1, myDelegateFn, MyStringDelegateCallbackFn); // error – someDelegateCallbackFn is not defined RegisterDelegate( class1, myDelegateFn, someDelegateCallbackFn); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1700 -------------------------------------------------------------------------------- # Compiler Error 1700 file error:  End of file reached The compiler reached the end of file before all functions or statements were completed. - Make sure all functions have matching opening and closing braces. - Make sure all statement expressions have matching opening and closing parenthesis. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1701 -------------------------------------------------------------------------------- # Compiler Error 1701 file error:  Error writing header file: '\'                    Error writing file: '\'                    Error writing library file                    Error writing output file                    Error creating compiler makefile: '\'                    Error opening compiler source makefile: '\'                    Error opening source file: '\' The specified file could not be opened or created. - Make sure there is sufficient disk space for the file to be written. - If including a User or Crestron Library (#USER_LIBRARY or #CRESTRON_LIBRARY), make sure the library file name is valid, spelled properly and does not contain the file extension (.usl or .csl). - Make sure the latest version of the Crestron Database is installed. - Make sure the path for the Crestron Database and User SIMPL+ files have been specified within SIMPL. - Make sure the file does not exist with a Read-Only attribute. - Make sure another application (i.e.: another instance of SIMPL+) is not currently running with this file open. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1702 -------------------------------------------------------------------------------- # Compiler Error 1702 file error:  Error extracting library, '\', from archive: '\' The specified file was not found within the Crestron Library archive. - Make sure the library file name is valid, spelled properly and does not contain the file extension (.csl). - Make sure the latest version of the Crestron Database is installed. - Make sure the path for the Crestron Database has been specified within SIMPL. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1703 -------------------------------------------------------------------------------- # Compiler Error 1703 library error:  Error:  Library names cannot contain path When including User or Crestron libraries, only the library name is needed within the functions, #USER_LIBRARY and #CRESTRON_LIBRARY.   Passing in a fully qualified path is not allowed. The following are examples of this error: #USER_LIBRARY “MyLibrary” // ok – no path is given #USER_LIBRARY “C:\MyPath\MyLibrary” // error – C:\MyPath\\ should not be specified -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1704 -------------------------------------------------------------------------------- # Compiler Error 1704 library error:  Error:  Library name cannot be the same as the module symbol name Library names must be unique.  They cannot have the same name as the SIMPL+ module. The following are examples of this error: #SYMBOL_NAME “CommonFns” #USER_LIBRARY “CommonFns” // error – same name as #SYMBOL_NAME #USER_LIBRARY “LibraryFns” // ok -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1705 -------------------------------------------------------------------------------- # Compiler Error 1705 **library error: Error generating header file for SIMPL# Library: ‘\’** **F**atal Error. SIMPL+ does not recognize a construct within the SIMPL# Library. Please report this issue to Crestron. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1706 -------------------------------------------------------------------------------- # Compiler Error 1706 **library error: Error including SIMPL# Library: ‘\’** A problem exists within a SIMPL# Library. This could be due to a signing issue or the SIMPL# Library being built incorrectly. The SIMPL# Library should be rebuilt again. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Error 1707 -------------------------------------------------------------------------------- # Compiler Error 1707 **library error:  Error:  Library path cannot contain relative or absolute paths: '\'.  (use #INCLUDEPATH instead)** Fully-qualified paths and relative paths cannot be used when including SIMPL# Libraries.  Only the library name can be specified within the include directive. The following are examples of this error: // Module1.usp `#USER_SIMPLSHARP_LIBRARY “MyLibrary” // ok – no path is given` `#USER_SIMPLSHARP_LIBRARY “C:\MyPath\MyLibrary” // error – fully-qualified path specified` `#USER_LIBRARY “..\..\MyPath\MyLibrary” // error – relative path specified` `// Module2.usp` `#INCLUDEPATH “C:\\MyLibraries”` `#INCLUDEPATH “..\\..\\Projects”` `#USER_SIMPLSHARP_LIBRARY “MySSharpLibrary” // ok` `#USER_LIBRARY “MySPlusLibrary” // ok` -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Errors and Warnings Overview > Compiler Errors and Warnings Overview -------------------------------------------------------------------------------- # Compiler Errors and Warnings Overview Of all the possible problems that a program can have, compiler errors and warnings may be the easiest to remedy. This is because the compiler reveals both the nature and location of the problems it encounters. The only task left to the developer 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, it is recommended that you 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. The SIMPL+ program compiler errors and warnings are grouped into several categories, as shown in the following table. Errors are listed in numerical order; the numbers are linked to detailed descriptions of the errors. Compiler Errors and Warnings | CATEGORY | NUMBER | MESSAGE TEXT | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | | Syntax Errors | 1000 | '' already defined | | 1001 | Undefined variable: '' Undefined function ‘’ | | | 1002 | Missing '' | | | 1003 | Incorrect type '', expected type(s): '' Incorrect type, expected type(s): '' | | | 1004 | Unmatched symbol: '' | | | 1005 | Unexpected symbol in compiler directive: '' | | | 1006 | Invalid #DEFINE_CONSTANT value: '' | | | 1007 | Missing array index: '' | | | 1008 | Invalid integer argument or undefined variable: '' | | | 1009 | Missing structure member: '' Structure does not contain member: '' | | | 1010 | Symbol Name contains illegal character: ';' | | | 1011 | Missing return value | | | 1012 | Unterminated string constant | | | 1013 | Source code does not evaluate to anything | | | 1014 | The compiler was expecting a parameter type variable and another declaration type or token was found. | | | 1015 | The compiler was expecting a parameter unit and another token or type was found. | | | 1016 | The compiler was expecting a parameter property and another token or type was found. | | | 1017 | Syntax error: SIMPL# Classes and Structures are case-sensitive: ‘’ | | | Fatal Errors | 1100 | Statement outside of function scope | | 1101 | Abort - Error count exceeded | | | Expression Errors | 1200 | Invalid numeric expression: '' Invalid string expression Invalid expression: '' | | 1201 | Invalid \\x sequence Invalid \\x sequence: '' | | | Declaration Errors | 1300 | Array size missing Array size invalid | | 1301 | Invalid array index | | | 1302 | Variable name, ‘’, exceeds maximum length of characters | | | 1303 | Declaration type not allowed within structure: '' Structure cannot contain String Arrays or Structure variables: '' Structure definitions not allowed within other structures Local Structure declarations are not allowed | | | 1304 | Local variables must be declared at top of function | | | 1305 | Local functions not supported | | | 1306 | Declaration type can only be used globally: '' | | | 1307 | Variables must be declared before array declarations: '' | | | 1308 | Global variable declaration cannot be declared in library file: '' I/O Declaration cannot be declared in library file: '' | | | 1309 | Compiler Directive must be set before all global variable declarations #DEFAULT_NONVOLATILE Compiler Directive already set #DEFAULT_VOLATILE Compiler Directive already set | | | 1310 | Compiler directive cannot be in function scope | | | 1311 | Undefined Wait Label: '' Missing, invalid or already defined Wait label: '' | | | 1312 | Array boundary exceeded maximum size of ‘num_bytes’ bytes | | | 1313 | Minimum array size invalid | | | 1314 | Minimum array size is not allowed for this datatype: '' Minimum array size for this datatype has already been declared: ' | | | 1315 | The receiving buffer size was not specified within the socket declaration. All socket declarations must contain a buffer size. | | | 1316 | An invalid Parameter Type was specified within a parameter declaration. | | | 1317 | A variable was found trying to be declared with the NONVOLATILE keyword. | | | 1318 | A parameter was being assigned a value that was either out of range or of the wrong type. | | | 1319 | A parameter was being assigned a value that was either out of range or of the wrong type. | | | 1320 | The property unit, unitString, cannot be combined with any other property unit (i.e., unitDecimal,unitCharacter, etc). | | | 1321 | The declaration keyword, Dynamic, can only be used when #DEFAULT_VOLATILE is specified for the program module. | | | 1322 | The declaration keyword, Dynamic, can only be used with string or array declarations. I/O declarations are not allowed to be declared as dynamic. | | | 1323 | In order to declare Strings and Arrays dynamically, the compiler directive, #ENABLE_DYNAMIC, must be specified beforehand within the module. | | | 1324 | propList cannot be used in conjunction with propBounds. propBounds cannot be used in conjunction with propList. | | | 1325 | Default values, if specified, must be specified before a propList declaration. If using propBounds, the Default Value must be defined beforehand. If a default value is specified, the propList must contain at least one element that contains this default value. | | | 1326 | The Default Value must be within the bounds specified in propBounds. The compiler will also enforce that the lower bound is less than the upper bound. All values specified must also be of the type indicated within propValidUnits. | | | 1327 | Variables that are declared as volatile are only allowed to be resized. Either the global compiler directive, #VOLATILE, or the declaration modifier, “VOLATILE”, may be used to declare a variable as volatile. | | | 1328 | Encoding only applies to strings. The declaration modifiers, ASCII, UTF16 and INHERIT can only be used with variables of type STRING. | | | 1329 | Declaration error: Class name exists in one or more namespaces. Fully-qualified name must be specified: ‘’ | | | Assignment Errors | 1400 | Illegal Assignment | | 1401 | Variable cannot be used for assignment: '' | | | 1402 | Variable can only be used for assignment: '' | | | Function Argument Errors | 1500 | Argument cannot be passed by reference | | 1501 | Argument cannot be passed by value | | | 1502 | Function contains incomplete number of arguments Function call contains an unmatched number of arguments | | | 1503 | Input or Output signal expected: '' | | | 1504 | Incomplete number of format string arguments Format string contains an unmatched number of arguments Argument is missing or invalid. Argument is missing or invalid. expected | | | 1505 | Format string contains invalid format specifier | | | 1506 | 0, 1 or 2 constant expected for argument 1 | | | 1507 | Argument : Missing or invalid array | | | 1508 | I/O variable cannot be passed to read file functions: '' | | | 1509 | A valid class name was expected for a function argument and was not found. | | | 1510 | A valid class event handler was expected for a function argument and was not found. | | | Construct Errors | 1600 | 'Function Main' cannot contain function parameters 'Function Main' cannot return a value | | 1601 | Duplicate CASE Statement Constant expected: '' | | | 1602 | Switch statement contains 'default' without 'case' labels | | | 1603 | #CATEGORY does not exist: '' Defaulting to Category Type, ""32"" (Miscellaneous). | | | 1604 | 'EVENT' already has a body | | | 1605 | Function can only be contained within an event | | | 1606 | Statement must be contained within a loop statement | | | 1607 | GetLastModifiedArrayIndex may return an ambiguous signal index | | | 1608 | Missing library file name | | | 1609 | The compiler encountered this function call outside of Function Main | | | 1610 | The compiler encountered this function call within a Wait Statement. | | | 1611 | An invalid structure type was encountered within a construct. | | | 1612 | Custom category names can only be assigned to category “46”. A different category number was found. | | | 1613 | SocketGetSenderIPAddress can only be used within the SOCKETRECEIVE event. It cannot be used inside any other declared function or event type. | | | 1614 | SocketGetStatus can only be used within the SOCKETSTATUS event. It cannot be used inside any other declared function or event type. | | | 1615 | The functions, GetExcpetionMessage and GetExceptionCode can only be used within the CATCH portion of a TRY-CATCH statement block. It cannot be used inside any other type of statement block or event handler. | | | 1616 | When registering delegates, the callback function specified must be valid and exist within the SIMPL+ module. The delegate callback function’s signature must match the signature within the SIMPL# Library. | | | File Errors | 1700 | End of file reached | | 1701 | Error writing header file: '' Error writing file: '' Error writing library file Error writing output file Error creating compiler makefile: '' Error opening compiler source makefile: '' Error opening source file: '' | | | 1702 | Error extracting library, '', from archive: '' | | | 1703 | When including User or Crestron libraries, only the library name is needed within the functions, #USER_LIBRARY and #CRESTRON_LIBRARY. Passing in a fully qualified path is not allowed. | | | 1704 | Library names must be unique. They cannot have the same name as the SIMPL+ module. | | | 1705 | Fatal Error.SIMPL+ does not recognize a construct within the SIMPL# Library. | | | 1706 | A problem exists within a SIMPL# Library. This could be due to a signing issue or the SIMPL# Library being built incorrectly. The SIMPL# Library should be rebuilt again. | | | 1707 | Library error: Library path cannot be relative: . Absolute paths may be used. | | | Compiler Warnings | 1019 | Logic excluded as a result of #if_series3 directive | | 1800 | 'Return' statement will only terminate current Wait statement's function scope | | | 1801 | 'TerminateEvent' statement will only terminate current Wait statement's function scope | | | 1802 | #CATEGORY_NAME defined more than once. Using: #CATEGORY_NAME "" | | | 1803 | Possible data loss: LONG_INTEGER to INTEGER assignment | | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Warning 1019 -------------------------------------------------------------------------------- # Compiler Warning 1019 compiler warning:  Logic excluded as a result of #if_series3 directive SIMPL+ module(s) contain the #IF_SERIES3 directive. When compiling for 4-Series control systems any logic within the #IF_SERIES3 directive block will be excluded from compilation which may result in loss of functionality. Review the logic contained within the #IF_SERIES3 directive and make sure that it doesn't include any logic intended for 4-series control systems. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Warning 1800 -------------------------------------------------------------------------------- # Compiler Warning 1800 compiler warning:  'Return' statement will only terminate current                                       Wait statement's function scope A ‘Return’ statement within a Wait Statement’s block of code will cause the Wait Statement to terminate.  It will NOT terminate the current function that the Wait Statement resides within. Wait Statements are similar to event functions (EVENT, PUSH, CHANGE, RELEASE) in that they execute in their own program thread.  The control system can have many threads executing at the same time;  each thread runs concurrent with one another. The following are examples of this warning: FUNCTION MyFunc( INTEGER x ) {    if ( x == 1 )    {       Wait( 500 )       {          return;      // warning - this will terminate the                       //           Wait Statement. It will NOT                       //           terminate MyFunc()       }    }    else if ( x == 2 )       return;         // this will terminate MyFunc()    x = x + 1; } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Warning 1801 -------------------------------------------------------------------------------- # Compiler Warning 1801 compiler warning:  'TerminateEvent' statement will only terminate current                                       Wait statement's function scope When Wait Statements are embedded within one another, the TerminateEvent, will only terminate the corresponding Wait Statement of the same scope.  It will NOT terminate any Wait Statements that are of a different scope. Wait Statements are similar to event functions (EVENT, PUSH, CHANGE, RELEASE) in that they execute in their own program thread.  The control system can have many threads executing at the same time;  each thread runs concurrent with one another. Scope refers to the level at which an Event, user-defined function or statement resides.  Having a global scope means that the function or variable can be called or accessed from anywhere within the program.  A local scope means that the variable can only be accessed from within the event or function that it resides in. The following are examples of this warning: FUNCTION MyFunc( INTEGER x ) {    Wait( 500, MyLabel1 )    {       Wait( 300, MyLabel2 )       {          TerminateEvent;    // warning – this will only terminate                             //           the Wait Statent, MyLabel2.                             //           MyLabel1 will continue to                             //           execute       }    } } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Warning 1802 -------------------------------------------------------------------------------- # Compiler Warning 1802 compiler warning:  #CATEGORY_NAME defined more than once.                                       Using: #CATEGORY_NAME "\" Only one category name is allowed for each SIMPL+ module.  If the compiler directive, #CATEGORY, is found more than once within a SIMPL+ module, the compiler will use the category number from the last occurrence of the compiler directive. The following are examples of this warning: #CATEGORY “1” #CATEGORY “2” FUNCTION MyFunc() { } #CATEGORY “3”          // this is the resulting category number                        // for this SIMPL+ module FUNCTION AnotherFunc() { } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Compiler Errors & Warnings > Compiler Warning 1803 -------------------------------------------------------------------------------- # Compiler Warning 1803 compiler warning:  Possible data loss: LONG_INTEGER to INTEGER assignment A LONG_INTEGER result was assigned to an INTEGER variable or passed to a function for an INTEGER parameter.  The 32-bit LONG_INTEGER will be truncated to 16-bit value and assigned to the integer, resulting in a loss of data. - Make sure all the datatypes within an expression are of the same datatype. - Make sure the parameter of a function being called is of the same datatype as the argument being passed in. - Make sure the return value of a function matches the destination’s datatype. The following are examples of this warning: LONG_FUNCTION MyFunc( INTEGER x ) {    INTEGER i;    LONG_INTEGER j;    i = i;            // ok – both sides of the assigment are of                      //      the same datatype    j = i;            // ok – no loss of data    j = j;            // ok – both sides of the assigment are of                      //      the same datatype    i = j;            // warning – LONG_INTEGER being assigned to                      //           an INTEGER    Call MyFunc( i ); // ok    Call MyFunc( j ); // warning    i = MyFunc( 5 );  // warning – the integer, i, is being assigned a                      //           LONG_INTEGER value } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > ATOI > Atoi -------------------------------------------------------------------------------- # Atoi Name: Atoi Syntax:     INTEGER Atoi(STRING SOURCE); Description: Converts a STRING to an INTEGER value. The conversion looks for the first valid character (0-9), and then reads until it finds the first invalid character. The resulting string of valid characters is then converted. The "-" is ignored, hence the output is an unsigned number [i.e., ATOI("-1") would yield 1 as the output]. If the value exceeds 65535, the value is undefined. If no valid value to convert is found, 0 is returned. Parameters: SOURCE is a string containing characters that range from 0 to 9 to be converted. The result will be an unsigned number from 0 to 65535. Return Value: An integer representing the given string value. Example:     STRING_INPUT IN$[100];     INTEGER VAL;     CHANGE IN$     {       VAL = ATOI(IN$);       PRINT("Value of %s after ATOI is %d\n", IN$, VAL);     } For example, if IN$ is "abc1234xyz", then VAL will hold the integer 1234. If IN$ is "-50", then VAL will hold the integer 50. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > ATOL > Atol -------------------------------------------------------------------------------- # Atol Name: Atol Syntax:     LONG_INTEGER Atol(STRING SOURCE); Description: Converts a STRING to an LONG_INTEGER value. The conversion looks for the first valid character (0-9), and then reads until it finds the first invalid character. The resulting string of valid characters is then converted. The "-" is ignored, hence the output is an unsigned number [i.e., ATOL("-1") would yield 1 as the output]. If no valid value to convert is found, 0 is returned. If the integer would exceed 32 bits, the value returned is undefined. Parameters: SOURCE is a string containing characters that range from 0 to 9 to be converted. The result will be an unsigned number from 0 to 4294967295. Return Value: A long integer representing the given string value. Example:     STRING_INPUT IN$[100];     LONG_INTEGER VAL;     CHANGE IN$     {       VAL = ATOL(IN$);       PRINT("Value of %s after ATOL is %ld\n", IN$, VAL);     } For example, if IN$ is "abc1234xyz", then VAL will hold the number 1234. If IN$ is "-50", then VAL will hold the number 50. Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > Chr -------------------------------------------------------------------------------- # Chr Name: Chr Syntax:     STRING Chr(INTEGER CODE); Description: Takes the integer value specified and returns the corresponding ASCII character as a one-byte string. Parameters: CODE contains a number from 0 to 255 to be converted into an ASCII string. Return Value: A string representing the code. If CODE is greater than 255, lower 8-bits of CODE are used in the computation. Example:     STRING_OUTPUT Code$;     ANALOG_INPUT VALUE;     CHANGE VALUE     {       Code$ = CHR(VALUE);       PRINT("Code = %s\n", Code$);     } In this example, if VALUE was equal to 72, the output would be Code = H. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > Datatype Conversions -------------------------------------------------------------------------------- # Datatype Conversions | Source | Destination | Action | | ------------------- | ------------------- | ------------------------------------------------------------------------------------ | | INTEGER | LONG_INTEGER | Lower 2 bytes of destination = source. Upper 2 bytes cleared. | | INTEGER | SIGNED_INTEGER | The 2 bytes of source moved to destination. 2 byte number now treated as signed. | | INTEGER | SIGNED_LONG_INTEGER | Lower 2 bytes of destination = source. Upper 2 bytes cleared. | | LONG_INTEGER | INTEGER | Lower 2 bytes of source moved to destination, treated as unsigned. | | LONG_INTEGER | SIGNED_INTEGER | Lower 2 bytes of source moved to destination, treated as signed. | | LONG_INTEGER | SIGNED_LONG_INTEGER | The 4 bytes of destination = source, now treated as signed. | | SIGNED_LONG_INTEGER | INTEGER | Lower 2 bytes of source moved to destination. | | SIGNED_LONG_INTEGER | SIGNED_INTEGER | Lower 2 bytes of source moved to destination. | | SIGNED_LONG_INTEGER | LONG_INTEGER | The 4 bytes of destination = source, now treated as unsigned. | | SIGNED_INTEGER | INTEGER | Lower 2 bytes of source moved to destination, 2 byte number now treated as unsigned. | | SIGNED_INTEGER | LONG_INTEGER | 2 byte source is sign extended to 4 bytes | | SIGNED_INTEGER | SIGNED_LONG_INTEGER | 2 byte source is sign extended to 4 bytes | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > HexToI -------------------------------------------------------------------------------- # HexToI Name: HexToI Syntax:     INTEGER HexToI(STRING Source); Description: Returns the INTEGER value of Source.  If Source exceeds 4 characters, the lower 4 characters of Source are used.   Parameters: STRING Source:  A string containing the characters are 0 through 9, A through F, and a through f.  If other characters are in the string, the result is undefined or zero, depending on the SIMPL+ Cross Compiler Include File version. Return Value: An integer representing the given string value. If the source string contains characters other than A-F, a-f, 0-9 the result will be undefined if the SIMPL+ Cross Compiler Include file is less than version 1.45, or zero if the SIMPL+ Cross Compiler Include file is version 1.45 or later. The Cross Compiler Include File version can be determined from the SIMPL+ Editor, under Help | About. Example:    INTEGER V1, V2;    V1 = HexToI("ABCD");    V2 = HexToI("ABCDE"); // Only BCDE will be in the conversion.    PRINT("V1=%u, V2=%u\n", V1, V2); For example,  the code shown above would return: V1=43981, V2=48350 Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > HexToL -------------------------------------------------------------------------------- # HexToL Name: HexToL Syntax:     LONG_INTEGER HexToL(STRING Source); Description: Returns the LONG_INTEGER value of Source.  If Source exceeds 8 characters, the lower 8 characters of Source are used.   Parameters: STRING Source:  A string containing the characters are 0 through 9, A through F, and a through f.  If other characters are in the string, the result is undefined or zero, depending on the SIMPL+ Cross Compiler Include File version. Return Value: A LONG_INTEGER containing the string value. If the source string contains characters other than A-F, a-f, 0-9 the result will be undefined if the SIMPL+ Cross Compiler Include file is less than version 1.45, or zero if the SIMPL+ Cross Compiler Include file is version 1.45 or later. The Cross Compiler Include File version can be determined from the SIMPL+ Editor, under Help | About. Example:    LONG_INTEGER V1, V2;    V1 = HexToL("ABCD1234");    V2 = HexToL("ABCD12340"); // Only BCD12340 will be in the conversion.    PRINT("V1=%lu, V2=%lu\n", V1, V2); For example,  the code shown above would return: V1= 2882343476, V2= 3167822656 Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > HexToSI -------------------------------------------------------------------------------- # HexToSI Name: HexToSI Syntax:     SIGNED_INTEGER HexToSI (STRING Source); Description: Returns the SIGNED_INTEGER value of Source.  If Source exceeds 4 characters, the lower 4 characters of Source are used.   Parameters: STRING Source:  A string containing the characters are 0 through 9, A through F, and a through f.  If other characters are in the string, the result is undefined or zero, depending on the SIMPL+ Cross Compiler Include File version. Return Value: A SIGNED_INTEGER containing the string value. If the source string contains characters other than A-F, a-f, 0-9 the result will be undefined if the SIMPL+ Cross Compiler Include file is less than version 1.45, or zero if the SIMPL+ Cross Compiler Include file is version 1.45 or later. The Cross Compiler Include File version can be determined from the SIMPL+ Editor, under Help | About. Example:    SIGNED_INTEGER V1, V2;    V1 = HexToSI ("FFFF");    V2 = HexToSI ("AFFFB); // Only FFFB will be in the conversion.    PRINT("V1=%d, V2=%d\n", V1, V2); For example,  the code shown above would return: V1=-1, V2=-5 Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > HexToSL -------------------------------------------------------------------------------- # HexToSL Name: HexToSL Syntax:     SIGNED_LONG_INTEGER HexToL(STRING Source); Description: Returns the SIGNED_LONG_INTEGER value of Source.  If Source exceeds 8 characters, the lower 8 characters of Source are used.   Parameters: STRING Source:  A string containing the characters are 0 through 9, A through F, and a through f.  If other characters are in the string, the result is undefined or zero, depending on the SIMPL+ Cross Compiler Include File version. Return Value: A SIGNED_LONG_INTEGER containing the string value. If the source string contains characters other than A-F, a-f, 0-9 the result will be undefined if the SIMPL+ Cross Compiler Include file is less than version 1.45, or zero if the SIMPL+ Cross Compiler Include file is version 1.45 or later. The Cross Compiler Include File version can be determined from the SIMPL+ Editor, under Help | About. Example:    SIGNED_LONG_INTEGER V1, V2;    V1 = HexToSL("FFFF1234");    V2 = HexToSL("FFFF12340"); // Only FFF12340 will be in the conversion.    PRINT("V1=%ld, V2=%ld\n", V1, V2); For example,  the code shown above would return: V1=-60876, V2=-974016 Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > ITOA > ItoA -------------------------------------------------------------------------------- # ItoA Name: ItoA Syntax:     STRING ItoA(INTEGER CODE); Description: Takes the value in CODE and creates a string containing the string equivalent of that integer. The output string does not contain leading zeros. Parameters: CODE contains a number from 0 to 65535 to be converted into a string. CODE is treated as an unsigned number. Return Value: A string representing the code. If CODE is greater than 65535, lower 16-bits of CODE are used in the computation. Note that the following two statements are equivalent:     out$ = itoa(CODE);     makestring(out$, "%d", CODE); Example:     STRING_OUTPUT Code$;     ANALOG_INPUT VALUE;     CHANGE VALUE     {       Code$ = ITOA(VALUE);       PRINT("Code$ = %s\n", ITOA(VALUE);     } For example, if VALUE was equal to 25, Code$ would contain the string "25". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > ITOHEX > ItoHex -------------------------------------------------------------------------------- # ItoHex Name: ItoHex Syntax:     STRING ITOHEX(INTEGER CODE); Description: Takes the value in CODE and creates a string containing the hexadecimal equivalent. The output string does not contain leading zeros and is expressed in uppercase. Parameters: CODE contains a number from 0 to 65535 to be converted into a hexadecimal string. CODE is treated as an unsigned number. Return Value: A string representing the code. If CODE is greater than 65535, lower 16-bits of CODE are used in the computation. Note that the following two statements are equivalent:     out$ = itohex(CODE);     makestring(out$, "%X", CODE); Example:     STRING_OUTPUT Code$;     ANALOG_INPUT VALUE;     CHANGE VALUE     {       Code$ = ITOHEX(VALUE);       PRINT("Code$ = %s\n", ITOHEX(VALUE);     } For example, if VALUE contained the integer 90, Code$ would contain the string "5A". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > LtoA -------------------------------------------------------------------------------- # LtoA Name: LtoA Syntax:     STRING LtoA(LONG_INTEGER CODE); Description: Takes the value in CODE and creates a string containing the string equivalent of that LONG_INTEGER. The output string does not contain leading zeros. Parameters: CODE contains a number from 0 to 4294967295 to be converted into a string. CODE is treated as an unsigned number. Return Value: A string representing the code. Note that the following two statements are equivalent:     out$ = ltoa(CODE);     makestring(out$, "%ld", CODE); Example:     STRING_OUTPUT Code$;     LONG_INTEGER VALUE;     CHANGE VALUE     {       Code$ = LTOA(VALUE);       PRINT("Code = %s\n", Code$);     } For example, if VALUE was equal to 25, Code$ would contain the string "25". Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > LtoHex -------------------------------------------------------------------------------- # LtoHex Name: LtoHex Syntax:     STRING LTOHEX(LONG_INTEGER CODE); Description: Takes the value in CODE and creates a string containing the hexadecimal equivalent. The output string does not contain leading zeros and is expressed in uppercase. Parameters: CODE contains a number from 0 to 4294967295 to be converted into a hexadecimal string. CODE is treated as an unsigned number. Return Value: A string representing the code. Note that the following two statements are equivalent:     out$ = ltohex(CODE);     makestring(out$, "%X", CODE); Example:     STRING_OUTPUT Code$;     LONG_INTEGER VALUE;     CHANGE VALUE     {       Code$ = LTOHEX(VALUE);       PRINT("Code = %s\n", Code$);     } For example, if VALUE contained the integer 90, Code$ would contain the string "5A". Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Data Conversion Functions > Overview > Data Conversion Functions Overview -------------------------------------------------------------------------------- # Data Conversion Functions Overview These functions take one form of data (integer or string) and convert it to the opposite type in a given SIMPL+ program. Usually, these functions are for converting number stored in strings to integers, or for converting numbers stored in integers to strings. | | | |----|----| | Function | Description | | [ATOI] | Converts a STRING to an INTEGER value. | | [ATOL] | Converts a STRING to an LONG_INTEGER value. | | [Chr] | Takes the integer value specified and returns the corresponding ASCII character as a one-byte string. | | [HexToI] | Returns the INTEGER value of Source.  If Source exceeds 4 characters, the lower 4 characters of Source are used.   | | [HexToL] | Returns the LONG_INTEGER value of Source.  If Source exceeds 8 characters, the lower 8 characters of Source are used.   | | [HexToSI] | Returns the SIGNED_INTEGER value of Source.  If Source exceeds 4 characters, the lower 4 characters of Source are used.   | | [HexToSL] | Returns the SIGNED_LONG_INTEGER value of Source.  If Source exceeds 8 characters, the lower 8 characters of Source are used.   | | [ITOA] | Takes the value in CODE and creates a string containing the string equivalent of that integer. | | [ITOAHex] | Takes the value in CODE and creates a string containing the hexadecimal equivalent. | | [LtoA] | Takes the value in CODE and creates a string containing the string equivalent of that LONG_INTEGER. | | [LtoHex] | Takes the value in CODE and creates a string containing the hexadecimal equivalent. | [ATOI]: ATOI.md [ATOL]: ATOL.md [Chr]: Chr.md [HexToI]: HexToI.md [HexToL]: HexToL.md [HexToSI]: HexToSI.md [HexToSL]: HexToSL.md [ITOA]: ITOA.md [ITOAHex]: ITOHEX.md [LtoA]: LtoA.md [LtoHex]: LtoHex.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > ANALOG INPUT > ANALOG_INPUT -------------------------------------------------------------------------------- # ANALOG_INPUT Name: ANALOG_INPUT Syntax: ANALOG_INPUT \[,\...]; ANALOG_INPUT \; ANALOG_INPUT \]]\>    ANALOG_INPUT \[,[_SKIP_]][,\...]; Description: Routes analog inputs from the outside SIMPL program into a SIMPL+ program under with the specified variable names. ANALOG_INPUT values are 16-bit numbers. They are treated as signed or unsigned values inside of a SIMPL+ program depending on the operators or functions being used. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  ANALOG_INPUT variables may not be passed to functions in Version 3.00 for the 2-Series Control Systems. If you need to pass an ANALOG_INPUT variable to a function, assign it to a locally declared variable and pass that variable to the function. For an array of ANALOG_INPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of inputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: ANALOG_INPUT ramp1; Signifies that one analog input is coming into the SIMPL+ program from the SIMPL Program. ANALOG_INPUT light_levels[25]; Signifies that up to 25 analog inputs are coming into the SIMPL+ program from the SIMPL Program, referenced as light_levels[1] through light_levels[25]. One is shown as a minimum but the symbol input can be expanded by the user up to 25. ANALOG_INPUT temp_set_pts[20,4]; Signifies that up to 20 analog inputs exist, referenced as temp_set_pts[1] through temp_set_pts[20]. Four are shown at a minimum, and the symbol inputs can be expanded by the user up to 20. Version: X Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later for ANALOG_INPUT arrays 2-Series SIMPL v2.01.05 and later [Same features as X Generation SIMPL v1.50.06] SIMPL v2.03.18 and later for fixed arrays and minimum sizes. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > ANALOG OUTPUT > ANALOG_OUTPUT -------------------------------------------------------------------------------- # ANALOG_OUTPUT Name: ANALOG_OUTPUT Syntax: ANALOG_OUTPUT \[,\...]; ANALOG_OUTPUT \; ANALOG_OUTPUT\]]\>; ANALOG_OUTPUT \[,[_SKIP_]][,\...]; Description: Routes a value from the SIMPL+ program to the SIMPL program as an analog value. ANALOG_OUTPUT values are 16-bit numbers. They are treated as signed or unsigned values inside of a SIMPL+ program depending on the operators or functions being used. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  ANALOG_OUTPUTs may be jammed with other analog values from a SIMPL program (i.e., from a RAMP or other analog logic, even other SIMPL+ symbols). When such an output is jammed, the new value is read back into the SIMPL+ symbol and the value of the output is altered. In X-Generation Control Systems, the logic process only sees the last analog that was posted after the SIMPL+ module tasks switched away. Therefore, in a loop that iterates from 1 to 10000, only a few of the values will be seen by the logic process. If all values should be seen by the logic process, a PROCESSLOGIC statement is required after the assignment to the ANALOG_OUTPUT. When the SIMPL+ program writes to the ANALOG_OUTPUT, the new value is posted immediately. Therefore, if the value is read back after being assigned, the new value is read back (unlike a DIGITAL_OUTPUT on X-Generation control systems). In the 2-Series Control Systems, the logic process sees ALL values that are assigned to the ANALOG_OUTPUT. No PROCESSLOGIC is required. For an array of ANALOG_OUTPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of outputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: ANALOG_OUTPUT LEVEL; Signifies that one analog output is being sent from the SIMPL+ program to the SIMPL program. ANALOG_OUTPUT LEVELS[25]; Signifies that up to 25 analog outputs, referenced as LEVELS[1] through LEVELS[25] are being sent from the SIMPL+ program to the SIMPL program. ANALOG_OUTPUT LEVELS[25,5]; Signifies same as above, except that a minimum of 5 are shown at any time. NOTE:  If LEVEL or any of the elements from LEVELS is jammed from outside the symbol, it will take on that new jammed value. NOTE: You should use [isSignalDefined] to test whether the output is connected to an actual signal in the SIMPL program before assigning a value to it. If you assign a value and there is no signal, a message is placed in the system error log. Version: X-Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, support for ANALOG_OUTPUT arrays 2-Series SIMPL v2.01.05 and later  [Same support as X Generation SIMPL v1.50.06, however, ANALOG_OUTPUTs or ANALOG_OUTPUT Arrays cannot be passed by reference] SIMPL v2.03.18 and later, Fixed size arrays and minimum sizes. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md [isSignalDefined]: ../System_Interfacing/IsSignalDefined.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > BUFFER INPUT > BUFFER_INPUT -------------------------------------------------------------------------------- # BUFFER_INPUT Name: BUFFER_INPUT Syntax: BUFFER_INPUT \[,\...]; BUFFER_INPUT \; BUFFER_INPUT\]][max_length]\>; BUFFER_INPUT \[,[_SKIP_]][,\...]; Description: Routes serial inputs from the outside SIMPL program into a SIMPL+ program under the specified variable names. This is used when a serial string coming from a communications port needs to be processed by a SIMPL+ program. When new data comes in on a BUFFER_INPUT, the data is appended to the end of a BUFFER_INPUT. If the buffer is full, the contents are shifted up and the new data is appended to the end. This differs from STRING_INPUTs in that new data entering into a STRING_INPUT variable replaces the previous string contents. BUFFER_INPUTs may be processed with string handling functions. The GETC function may be used to read a character from the beginning of the buffer and shift the contents up by 1. Buffer inputs may be written to, so their data space may be used as a storage spot for doing something such as parsing through a string without declaring temporary storage. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  BUFFER_INPUT variables may not be passed to functions in Version 3.00 for the 2-Series Control Systems. If you need to pass a BUFFER_INPUT variable to a function, assign it to a locally declared variable and pass that variable to the function. MAX_LENGTH may be a value up to 255 in SIMPL+ Version 1.00. SIMPL+ Version 2.00 and later allow for MAX_LENGTH to be up to 65534. For an array of BUFFER_INPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of inputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: BUFFER_INPUT FromComPort[100]; Signifies that a 100 character buffer with the name "FromComPort" is specified as a BUFFER_INPUT. BUFFER_INPUT ComBuffers[2][100]; Signifies that two 100 character buffers have been set up that may be referenced with the names ComBuffers[1] through ComBuffers[2]. BUFFER_INPUT ComBuffers[2,2][100]; Same as above except both are always shown on the symbol. Version: X-Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, allow BUFFER_INPUT arrays and MAX_LENGTH to be 65535. 2 Series: SIMPL v2.03.18 and later, [Same as X Generation SIMPL v1.50.06, and allow Fixed size arrays and minimum sizes] [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > DIGITAL INPUT > DIGITAL_INPUT -------------------------------------------------------------------------------- # DIGITAL_INPUT Name: DIGITAL_INPUT Syntax: DIGITAL_INPUT \[,\...]; DIGITAL_INPUT \; DIGITAL_INPUT \; DIGITAL_INPUT \[,[_SKIP_]][,\...]; Description: Routes digital inputs from the outside SIMPL program into a SIMPL+ program under the specified variable names. DIGITAL_INPUT values are either 0 (digital low) or 1 (digital high). Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  DIGITAL_INPUT variables may not be passed to functions in Version 3.00 for the 2-Series Control Systems. If you need to pass a DIGITAL_INPUT variable to a function, assign it to a locally declared variable and pass that variable to the function. For an array of DIGITAL_INPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of inputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: DIGITAL_INPUT osc_in, toggle_in; Signifies that two digital inputs are coming into the SIMPL+ program from the SIMPL Program. DIGITAL_INPUT status_bits[8]; Signifies that eight digital inputs are coming into the SIMPL+ program from the SIMPL Program, referenced under the names status_bits[1] through status_bits[8]. DIGITAL_INPUT flags[8,2]; Signifies up to eight digital inputs, with at least two shown. Version: SIMPL+ Version 3.01 for fixed arrays and minimum sizes. SIMPL+ Version 2.00 for DIGITAL_INPUT arrays. SIMPL+ Version 1.00 for everything else. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > DIGITAL OUTPUT > DIGITAL_OUTPUT -------------------------------------------------------------------------------- # DIGITAL_OUTPUT Name: DIGITAL_OUTPUT Syntax: DIGITAL_OUTPUT \[,\...]; DIGITAL_OUTPUT \; DIGITAL_OUTPUT \]]\>; DIGITAL_OUTPUT \[,[_SKIP_]][,\...]; Description: Routes a value from the SIMPL+ program to a SIMPL program. If a value different from 0 is placed on a DIGITAL_OUTPUT, the digital signal in the SIMPL program is set high when the control system processes the logic. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  DIGITAL_OUTPUTs may be jammed with other digital values from a SIMPL program (i.e., from a BUFFER or other jammable digital logic, even other SIMPL+ symbols). When such an output is jammed, the new value is read back into the SIMPL+ symbol and the value of the output is altered. NOTE: You should use [isSignalDefined] to test whether the output is connected to an actual signal in the SIMPL program before assigning a value to it. If you assign a value and there is no signal, a message is placed in the system error log. In X-Generation Control Systems, if a new value is assigned to the DIGITAL_OUTPUT from the SIMPL+ program, the value read back from it within the SIMPL+ program will have the original state until the logic is serviced. For example, if a DIGITAL_OUTPUT has a value of 0, and the value 1 is written to it, the value read back will be 0 until the system processes the rest of the logic attached to that SIMPL+ symbol. This is unlike an ANALOG_OUTPUT. If every change of a DIGITAL_OUTPUT is required to be seen by the logic, a PROCESSLOGIC statement is required after the assignment to the DIGITAL_OUTPUT. In the 2-Series Control Systems, the logic process sees ALL values that are assigned to the DIGITAL_OUTPUT.  No PROCESSLOGIC is required.  As an example, if the following code is used in the 2-Series Control Systems:     DIGITAL_OUTPUT State1;     State1=1;     State1=0; The logic will end up seeing a short pulse. For an array of DIGITAL_OUTPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of outputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: DIGITAL_OUTPUT State1, State2; Signifies that two digital signals are to be sent to a SIMPL program from this SIMPL+ program. NOTE:  For example, if State1 is jammed high via a BUFFER from outside the SIMPL+ program, the value of State1 becomes 1 and should be handled accordingly in the SIMPL+ code. DIGITAL_OUTPUT state_bits[3]; Signifies that up to three digital signals are to be sent to a SIMPL program from this SIMPL+ program. The names are referenced as state_bits[1] through state_bits[3]. The same jamming rules apply as in the previous example. DIGITAL_OUTPUT state_bits[3,3]; Same as above except all three are always shown on the symbol. Version: X-Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, support for DIGITAL_OUTPUT arrays 2-Series SIMPL v2.01.05 and later  [Same support as X Generation SIMPL Winodws v1.50.06, however, DIGITAL_OUTPUTs or DIGITAL_OUTPUT Arrays cannot be passed by reference] SIMPL v2.03.18 and later, Fixed size arrays and minimum sizes. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md [isSignalDefined]: ../System_Interfacing/IsSignalDefined.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > Declarations Overview > Declarations Overview -------------------------------------------------------------------------------- # Declarations Overview Declarations control the name, type, and number of inputs and outputs on a SIMPL+ symbol. The name is shown as a cue on the symbol in SIMPL and is used as the variable name in the body of the SIMPL+ program. When the symbol is drawn in SIMPL, the inputs are shown in the order of DIGITAL_INPUTs, ANALOG_INPUTs, STRING_INPUTs. The outputs are shown in the order of DIGITAL_OUTPUTs, ANALOG_OUTPUTs, STRING_OUTPUTs. When specifying a declaration, several variable names can be put after a declaration or multiple declaration statements may be used.  For example:     ANALOG_INPUT val1, val2, val3; is equivalent to     ANALOG_INPUT val1, val2;     ANALOG_INPUT val3; Allowable I/O List Combinations: SIMPL+ Version 2.00 and later gives the ability to define arrays in the Input/Output Lists. SIMPL+ version 3.01 and later introduced the ability to declare multiple fixed-size arrays in the input/output lists, and a minimum expanded size to variable-size arrays. The following are the allowable combinations: - Zero or more DIGITAL_INPUTs - Zero or more DIGITAL_INPUT arrays, the last is variable-size, the others are fixed-size. - Zero or more ANALOG_INPUTs, STRING_INPUTs, or BUFFER_INPUTs in any combination. - Zero or more ANALOG_INPUT, STRING_INPUT, or BUFFER_INPUT array, the last is variable-size, the others are fixed-size. - Zero or more DIGITAL_OUTPUTs - Zero or more DIGITAL_OUTPUT array, the last is variable-size, the others are fixed-size. - Zero or more ANALOG_OUTPUTs, STRING_OUTPUTs in any combination. - Zero or more ANALOG_OUTPUT or STRING_OUTPUT array, the last is variable-size, the others are fixed-size. Fixed and Variable Size Arrays Although SIMPL+ symbols can only handle one variable size DIGITAL_INPUT array, one variable-size DIGITAL_OUTPUT array, one variable-size ANALOG/STRING/BUFFER input array, and one variable size ANALOG/STRING/OUTPUT array, it is convenient to be able to refer to other inputs and outputs with array notation. Therefore, SIMPL+ allows an unlimited number of fixed-size input or output arrays, that are essentially single input or output values but array notation can be used. Every member of these fixed-size arrays is always shown in the symbol. All arrays, except the last one of each kind, are fixed-size arrays. The last one is variable-size, meaning that the symbol initially shows the first array value. The user can press ALT+ to expand the symbol to its maximum number of array inputs or outputs. In addition, a minimum size can be declared in all variable-size arrays, meaning that the minimum number of array members is always shown, not just the first one, and the array can be expanded from there. NOTE: The minimum array size number must be from 1 to the size of the array. If a minimum array size is specified on any array, but it is the last one within any type, it will be a compile error. Example: DIGITAL_INPUT YesVotes[10] DIGITAL_INPUT NoVotes[10] DIGITAL_INPUT AbstainVotes[10,5]; The symbol will show 10 digital inputs labelled: YesVotes[1], YesVotes[2] ...YesVotes[10], followed by 10 more labelled: NoVotes[1], NoVotes[2] ...NoVotes[10], followed by 5 labelled: AbstainVotes[1], AbstainVotes[2] ...AbstainVotes[5]. You can continue to expand the last one up to AbstainVotes[10]. NOTE: SIMPL+ modules have at most two expandable lists of inputs and two expandable lists of outputs. The first expandable input list must contain the digital inputs. The second expandable list must contain the analogs, serials, and buffered inputs. The same goes for the outputs.  Within each list, all of the fixed (non-array ) inputs or outputs come first, followed by at most one array which is expandable. Predefined Names: The names "on" and "off" are reserved. Assigning "on" to a variable sets the variable to 1, assigning "off" sets that variable to 0. The following shows equivalent, given that VALUE is a DIGITAL_OUTPUT:     VALUE = 1;   and   VALUE = on;     VALUE = 0;   and   VALUE = off; The current available declarations are listed below: [ANALOG_INPUT] [ANALOG_OUTPUT] [ASCII] [BUFFER_INPUT] [DIGITAL_INPUT] [DIGITAL_OUTPUT] [INHERIT] [INTEGER] [LONG_INTEGER] [VOLATILE] [NONVOLATILE] [SIGNED_INTEGER] [SIGNED_LONG_INTEGER] [STRING] [STRING_INPUT] [STRING_OUTPUT] [STRUCTURES] [UTF16] [ANALOG_INPUT]: ANALOG_INPUT.md [ANALOG_OUTPUT]: ANALOG_OUTPUT.md [ASCII]: ../Encoding/ASCII.md [BUFFER_INPUT]: BUFFER_INPUT.md [DIGITAL_INPUT]: DIGITAL_INPUT.md [DIGITAL_OUTPUT]: DIGITAL_OUTPUT.md [INHERIT]: ../Encoding/Inherit.md [INTEGER]: INTEGER.md [LONG_INTEGER]: LONG_INTEGER.md [VOLATILE]: VOLATILE.md [NONVOLATILE]: NONVOLATILE.md [SIGNED_INTEGER]: SIGNED_INTEGER.md [SIGNED_LONG_INTEGER]: SIGNED_LONG_INTEGER.md [STRING]: STRING.md [STRING_INPUT]: STRING_INPUT.md [STRING_OUTPUT]: STRING_OUTPUT.md [STRUCTURES]: STRUCTURES.md [UTF16]: ../Encoding/UTF16.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > Dynamic > DYNAMIC -------------------------------------------------------------------------------- # DYNAMIC Name: DYNAMIC Syntax: DYNAMIC [\ | \ | \ | \]; Description: Compiler directive to allow the size of a declared array to be changed to a new size.  Global and Local Integer, String and Structure arrays can be declared as dynamic. Argument: string, integer array, string array, or structure_array Example: DYNAMIC STRING MyStr[10], MyStrArr[10][20]; DYNAMIC INTEGER MyInt[10], MyIntArr[10][20]; DYNAMIC tagMyStruct myStructArr[10]; Version: X-Generation Not Supported 2-Series SIMPL 2.10.24 or later   Requires CUZ 4.000 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > INTEGER -------------------------------------------------------------------------------- # INTEGER Name: INTEGER Syntax:     INTEGER \[,\...];     INTEGER \[size] [,\[size]…];     INTEGER \[rows1][columns1] [,\[rows2][columns2]…]; Description: The first form declares an integer value that is local to this SIMPL+ program. INTEGER values are 16-bit quantities and are treated the same as ANALOG_INPUT values.  When used with traditional comparison operators (not the "S" operators, such as S\<, etc) they are treated as being in the range of 0 to 65535. The second form declares a one-dimensional array of INTEGER values. The third form declares a two-dimensional array of INTEGER values. A two-dimensional array can be thought of as a table or matrix. The values for SIZE, ROWS, and COLUMNS may be up to 65534. An INTEGER array element may be used anywhere an INTEGER is legal. Array elements are referenced by using the name followed by [element] for one-dimensional arrays or [row][column] for two-dimensional arrays. The element number may range from 0 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[0], NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE:  (X-Gen) The values of INTEGERs declared outside of functions are non-volatile. If the system is powered down and up, the variables will take the previous values. If programs are changed and uploaded, the values are not preserved. NOTE:  (2-Series) INTEGERs can be volatile or non-volatile. The default is defined using the compiler directives #DEFAULT_NONVOLATILE or #DEFAULT_VOLATILE or overridden using the nonvolatile or volatile keywords. Example:     INTEGER temp_level; Specifies one locally declared INTEGER in this SIMPL+ program     INTEGER CommandBytes[2]; Specifies an array of three INTEGERS that can be referenced under the name CommandBytes. In pictorial form, it appears as: | | | | |-------------------|-------------------|-------------------| | CommandBytes[0] | CommandBytes[1] | CommandBytes[2] |       INTEGER Matrix[4][3]; Specifies a two-dimensional array of integers five rows deep by four columns wide. In pictorial form, it appears as: | | | | | |------------------|------------------|------------------|------------------| | Matrix[0][0] | Matrix[0][1] | Matrix[0][2] | Matrix[0][3] | | Matrix[1][0] | Matrix[1][1] | Matrix[1][2] | Matrix[1][3] | | Matrix[2][0] | Matrix[2][1] | Matrix[2][2] | Matrix[2][3] | | Matrix[3][0] | Matrix[3][1] | Matrix[3][2] | Matrix[3][3] | | Matrix[4][0] | Matrix[4][1] | Matrix[4][2] | Matrix[4][3] | NOTE:  The subscripts of an array may be an expression, i.e.: INTEGER location[5], room;                room = 2;                location[room] = 10; Version: X Generation: SIMPL v1.20.01 and later SIMPL v1.50.06 and later, allow INTEGER declarations inside of functions. 2-Series: SIMPL v2.01.05 and later (supports INTEGER declarations globally and inside functions) -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > INTEGER PARAMETER > INTEGER_PARAMETER -------------------------------------------------------------------------------- # INTEGER_PARAMETER Name: INTEGER_PARAMETER Syntax:     INTEGER_PARAMETER \[,\...];     INTEGER_PARAMETER \[size] [,\[size]…]; Description: The first form declares an INTEGER_PARAMETER value that is local to this SIMPL+ program.   The second form declares a one dimensional array of INTEGER_PARAMETER values. The values for SIZE may be up to 65534. The actual value for the parameter is entered as a parameter to the SIMPL+ module when the SIMPL+ module is used the SIMPL program.  The parameter has a default range of legal values.  Since parameters can be entered in various formats (percentage, hex, decimal, time, etc.), please see [Allowable Ranges for 2 Series Numeric Formats] to find the valid ranges for the various types. SIMPL+ Parameters may have further programmatic restrictions placed on them, similar to parameter property sheets for SIMPL modules.  The programmer can restrict the range, only allow certain values to be entered, assume default values, restrict types of units entered among others restrictions.  For more information, please see [Parameter Property Blocks] An INTEGER_PARAMETER array element may be used anywhere an INTEGER is legal, with the caveat that it may not be written to.  Array elements are referenced by using the name followed by [element]. The element number may range from 1 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE: The [_SKIP_] keyword can be used in INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example:     INTEGER_PARAMETER temp_level; Specifies one INTEGER_PARAMETER with the name temp_level in this SIMPL+ program     INTEGER_PARAMETER CommandBytes[2]; Specifies an array of two INTEGER_PARAMETERS that can be referenced under the name CommandBytes. NOTE:  The subscripts of an array may be any positive valid integral expression such as the one shown below. INTEGER_PARAMETER location[5], room; INTEGER var; var = 3; if(room\>0 && room \<= 5) {    print("The location is %d\n", location[var]); } print("The location is %d\n", location[room]); Version: X Generation: Not Supported. 2-Series: SIMPL v2.10.24 or later, CUZ 4.000 or later. [Allowable Ranges for 2 Series Numeric Formats]: ../../Allowable_Ranges_for_2_Series_Numeric_Formats.md [Parameter Property Blocks]: ../Compiler_Directives/PARAMETER_PROPERTIES.md [_SKIP_]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > LONG INTEGER > LONG_INTEGER -------------------------------------------------------------------------------- # LONG_INTEGER Name: LONG_INTEGER Syntax:     LONG_INTEGER \[,\...];     LONG_INTEGER \[size] [,\[size]…];     LONG_INTEGER \[rows1][columns1] [,\[rows2][columns2]…]; Description: The first form declares a long value that is local to this SIMPL+ program. LONG_INTEGER values are 32-bit quantities ranging from 0-4294967295. The second form declares a one-dimensional array of LONG_INTEGER values. The third form declares a two-dimensional array of LONG_INTEGER values. A two-dimensional array can be thought of as a table or matrix. The values for SIZE, ROWS, and COLUMNS may be up to 65534. A LONG_INTEGER array element may be used anywhere a LONG_INTEGER is legal. Array elements are referenced by using the name followed by [element] for one-dimensional arrays or [row][column] for two-dimensional arrays. The element number may range from 0 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[0], NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE:  (2-Series) LONG_INTEGERs can be volatile or non-volatile. The default is defined using the compiler directives #DEFAULT_NONVOLATILE or #DEFAULT_VOLATILE or overriden using the nonvolatile or volatile keywords. Example:     LONG_INTEGER temp_level; Specifies one locally declared LONG_INTEGER in this SIMPL+ program    LONG_INTEGER CommandBytes[2]; Specifies an array of three LONG_INTEGERs that can be referenced under the name CommandBytes. In pictorial form, it appears as: | | | | |-------------------|-------------------|-------------------| | CommandBytes[0] | CommandBytes[1] | CommandBytes[2] |       LONG_INTEGER Matrix[4][3]; Specifies a two-dimensional array of LONG_INTEGERs five rows deep by four columns wide. In pictorial form, it appears as: | | | | | |------------------|------------------|------------------|------------------| | Matrix[0][0] | Matrix[0][1] | Matrix[0][2] | Matrix[0][3] | | Matrix[1][0] | Matrix[1][1] | Matrix[1][2] | Matrix[1][3] | | Matrix[2][0] | Matrix[2][1] | Matrix[2][2] | Matrix[2][3] | | Matrix[3][0] | Matrix[3][1] | Matrix[3][2] | Matrix[3][3] | | Matrix[4][0] | Matrix[4][1] | Matrix[4][2] | Matrix[4][3] | NOTE:  The subscripts of an array may be an expression, i.e.:                LONG_INTEGER location[5], room;                room = 2;                location[room] = 10; Version: X Generation:  Not Supported 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > LONG INTEGER PARAMETER > LONG_INTEGER_PARAMETER -------------------------------------------------------------------------------- # LONG_INTEGER_PARAMETER Name: LONG_INTEGER_PARAMETER Syntax:     LONG_INTEGER_PARAMETER \[,\...];     LONG_INTEGER_PARAMETER \[size] [,\[size]…]; Description: The first form declares a LONG_INTEGER_PARAMETER value that is local to this SIMPL+ program.   The second form declares a one dimensional array of LONG_INTEGER_PARAMETER values. The values for SIZE may be up to 65534. The actual value for the parameter is entered as a parameter to the SIMPL+ module when the SIMPL+ module is used the SIMPL program.  The parameter has a default range of legal values.  Since parameters can be entered in various formats (percentage, hex, decimal, time, etc.), please see [Allowable Ranges for 2 Series Numeric Formats] to find the valid ranges for the various types. SIMPL+ Parameters may have further programmatic restrictions placed on them, similar to parameter property sheets for SIMPL modules.  The programmer can restrict the range, only allow certain values to be entered, assume default values, restrict types of units entered among others restrictions.  For more information, please see [Parameter Property Blocks] A LONG_INTEGER_PARAMETER array element may be used anywhere a LONG_INTEGER is legal, with the caveat that it may not be written to.  Array elements are referenced by using the name followed by [element]. The element number may range from 1 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE: The [_SKIP_] keyword can be used in INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example:     LONG_INTEGER_PARAMETER temp_level; Specifies one LONG_INTEGER_PARAMETER with the name temp_level in this SIMPL+ program     LONG_INTEGER_PARAMETER CommandBytes[2]; Specifies an array of two LONG_INTEGER_PARAMETERS that can be referenced under the name CommandBytes.  NOTE:  The subscripts of an array may be any positive valid integral expression as shown in the example below. INTEGER_PARAMETER location[5], room; LONG_INTEGER var; var = 3; if(room\>0 && room \<= 5) {    print("The location is %d\n", location[var]); } print("The location is %d\n", location[room]); Version: X Generation: Not Supported. 2-Series: SIMPL v2.10.24 or later, CUZ 4.000 or later. [Allowable Ranges for 2 Series Numeric Formats]: ../../Allowable_Ranges_for_2_Series_Numeric_Formats.md [Parameter Property Blocks]: ../Compiler_Directives/PARAMETER_PROPERTIES.md [_SKIP_]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > NONVOLATILE > Nonvolatile -------------------------------------------------------------------------------- # Nonvolatile Name: Nonvolatile Syntax:    Nonvolatile NOTE:  This is not a declaration but a declaration modifier. It works only in conjunction with another declaration keyword. Description: Global integer and string program variables will retain their value if hardware power is lost. Example:     Nonvolatile integer n;     Nonvolatile string s[100]; Version: X Generation:  Not Supported 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > SIGNED INTEGER > SIGNED_INTEGER -------------------------------------------------------------------------------- # SIGNED_INTEGER Name: SIGNED_INTEGER Syntax: SIGNED_INTEGER \[,\...]; SIGNED_INTEGER \[size] [,\[size]…]; SIGNED_INTEGER \[rows1][columns1] [,\[rows2][columns2]…]; Description: The first form declares an integer value that is local to this SIMPL+ program. SIGNED_INTEGER values are 16-bit quantities ranging from -32678 to 32767. The second form declares a one-dimensional array of SIGNED_INTEGER values. The third form declares a two-dimensional array of SIGNED_INTEGER values. A two-dimensional array can be thought of as a table or matrix. The values for SIZE, ROWS, and COLUMNS may be up to 65534. A SIGNED_INTEGER array element may be used anywhere an SIGNED_INTEGER is legal. Array elements are referenced by using the name followed by [element] for one-dimensional arrays or [row][column] for two-dimensional arrays. The element number may range from 0 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[0], NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE:  SIGNED_INTEGERs can be volatile or non-volatile. The default is defined using the compiler directives #DEFAULT_NONVOLATILE or #DEFAULT_VOLATILE or overriden using the nonvolatile or volatile keywords. Example: SIGNED_INTEGER temp_level; Specifies one locally declared SIGNED_INTEGER in this SIMPL+ program SIGNED_INTEGER CommandBytes[2]; Specifies an array of three SIGNED_INTEGERS that can be referenced under the name CommandBytes. In pictorial form, it appears as: | | | | |-------------------|-------------------|-------------------| | CommandBytes[0] | CommandBytes[1] | CommandBytes[2] | SIGNED_INTEGER Matrix[4][3]; Specifies a two-dimensional array of integers five rows deep by four columns wide. In pictorial form, it appears as: | | | | | |------------------|------------------|------------------|------------------| | Matrix[0][0] | Matrix[0][1] | Matrix[0][2] | Matrix[0][3] | | Matrix[1][0] | Matrix[1][1] | Matrix[1][2] | Matrix[1][3] | | Matrix[2][0] | Matrix[2][1] | Matrix[2][2] | Matrix[2][3] | | Matrix[3][0] | Matrix[3][1] | Matrix[3][2] | Matrix[3][3] | | Matrix[4][0] | Matrix[4][1] | Matrix[4][2] | Matrix[4][3] | NOTE:  The subscripts of an array may be an expression, i.e.:                SIGNED_INTEGER location[5], room;                room = 2;                location[room] = 10; Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > SIGNED INTEGER PARAMETER > SIGNED_INTEGER_PARAMETER -------------------------------------------------------------------------------- # SIGNED_INTEGER_PARAMETER Name: SIGNED_INTEGER_PARAMETER Syntax:     SIGNED_INTEGER_PARAMETER \[,\...];     SIGNED_INTEGER_PARAMETER \[size] [,\[size]…]; Description: The first form declares a SIGNED_INTEGER_PARAMETER value that is local to this SIMPL+ program.   The second form declares a one dimensional array of SIGNED_INTEGER_PARAMETER values. The values for SIZE may be up to 65534. The actual value for the parameter is entered as a parameter to the SIMPL+ module when the SIMPL+ module is used the SIMPL program.  The parameter has a default range of legal values.  Since parameters can be entered in various formats (percentage, hex, decimal, time, etc.), please see [Allowable Ranges for 2 Series Numeric Formats] to find the valid ranges for the various types. SIMPL+ Parameters may have further programmatic restrictions placed on them, similar to parameter property sheets for SIMPL modules.  The programmer can restrict the range, only allow certain values to be entered, assume default values, restrict types of units entered among others restrictions.  For more information, please see [Parameter Property Blocks] A SIGNED_INTEGER_PARAMETER array element may be used anywhere a SIGNED_INTEGER is legal, with the caveat that it may not be written to.  Array elements are referenced by using the name followed by [element]. The element number may range from 1 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE: The [_SKIP_] keyword can be used in INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example:     SIGNED_INTEGER_PARAMETER temp_level; Specifies one SIGNED_INTEGER_PARAMETER with the name temp_level in this SIMPL+ program     SIGNED_INTEGER_PARAMETER CommandBytes[2]; Specifies an array of two SIGNED_INTEGER_PARAMETERS that can be referenced under the name CommandBytes.  NOTE:  The subscripts of an array may be any positive valid integral expression as shown by the example below. SIGNED_INTEGER_PARAMETER location[5], room; SIGNED_INTEGER var; var = 3; if(room\>0 && room \<= 5) {    print("The location is %d\n", location[var]); } print("The location is %d\n", location[room]); Version: X Generation: Not Supported. 2-Series: SIMPL v2.10.24 or later, CUZ 4.000 or later. [Allowable Ranges for 2 Series Numeric Formats]: ../../Allowable_Ranges_for_2_Series_Numeric_Formats.md [Parameter Property Blocks]: ../Compiler_Directives/PARAMETER_PROPERTIES.md [_SKIP_]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > SIGNED LONG INTEGER > SIGNED_LONG_INTEGER -------------------------------------------------------------------------------- # SIGNED_LONG_INTEGER Name: SIGNED_LONG_INTEGER Syntax: SIGNED_LONG_INTEGER \[,\...];   SIGNED_LONG_INTEGER \[size] [,\[size]…];   SIGNED_LONG_INTEGER \[rows1][columns1] [,\[rows2][columns2]…]; Description: The first form declares a long value that is local to this SIMPL+ program. SIGNED_LONG_INTEGER values are 32-bit quantities ranging from -2,147,483,648 to 2,147,483,647. The second form declares a one-dimensional array of SIGNED_LONG_INTEGER values. The third form declares a two-dimensional array of SIGNED_LONG_INTEGERvalues. A two-dimensional array can be thought of as a table or matrix. The values for SIZE, ROWS, and COLUMNS may be up to 65534. A SIGNED_LONG_INTEGER array element may be used anywhere a SIGNED_LONG_INTEGER is legal. Array elements are referenced by using the name followed by [element] for one-dimensional arrays or [row][column] for two-dimensional arrays. The element number may range from 0 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[0], NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE:  (2-Series) SIGNED_LONG_INTEGERs can be volatile or non-volatile. The default is defined using the compiler directives #DEFAULT_NONVOLATILE or #DEFAULT_VOLATILE or overriden using the nonvolatile or volatile keywords. Example:    SIGNED_LONG_INTEGER temp_level; Specifies one locally declared SIGNED_LONG_INTEGER in this SIMPL+ program     SIGNED_LONG_INTEGER CommandBytes[2]; Specifies an array of three SIGNED_LONG_INTEGERs that can be referenced under the name CommandBytes. In pictorial form, it appears as: | | | | |-------------------|-------------------|-------------------| | CommandBytes[0] | CommandBytes[1] | CommandBytes[2] |     SIGNED_LONG_INTEGER Matrix[4][3]; Specifies a two-dimensional array of SIGNED_LONG_INTEGERs five rows deep by four columns wide. In pictorial form, it appears as: | | | | | |------------------|------------------|------------------|------------------| | Matrix[0][0] | Matrix[0][1] | Matrix[0][2] | Matrix[0][3] | | Matrix[1][0] | Matrix[1][1] | Matrix[1][2] | Matrix[1][3] | | Matrix[2][0] | Matrix[2][1] | Matrix[2][2] | Matrix[2][3] | | Matrix[3][0] | Matrix[3][1] | Matrix[3][2] | Matrix[3][3] | | Matrix[4][0] | Matrix[4][1] | Matrix[4][2] | Matrix[4][3] | NOTE:  The subscripts of an array may be an expression, i.e.:                SIGNED_LONG_INTEGER location[5], room;                room = 2;                location[room] = 10; Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > SIGNED LONG INTEGER PARAMETER > SIGNED_LONG_INTEGER_PARAMETER -------------------------------------------------------------------------------- # SIGNED_LONG_INTEGER_PARAMETER Name: SIGNED_LONG_INTEGER_PARAMETER Syntax:     SIGNED_LONG_INTEGER_PARAMETER \[,\...];     SIGNED_LONG_INTEGER_PARAMETER \[size] [,\[size]…]; Description: The first form declares a SIGNED_LONG_INTEGER_PARAMETER value that is local to this SIMPL+ program.   The second form declares a one dimensional array of SIGNED_LONG_INTEGER_PARAMETER values. The values for SIZE may be up to 65534. The actual value for the parameter is entered as a parameter to the SIMPL+ module when the SIMPL+ module is used the SIMPL program.  The parameter has a default range of legal values.  Since parameters can be entered in various formats (percentage, hex, decimal, time, etc.), please see [Allowable Ranges for 2 Series Numeric Formats] to find the valid ranges for the various types. SIMPL+ Parameters may have further programmatic restrictions placed on them, similar to parameter property sheets for SIMPL modules.  The programmer can restrict the range, only allow certain values to be entered, assume default values, restrict types of units entered among others restrictions.  For more information, please see [Parameter Property Blocks] A SIGNED_LONG_INTEGER_PARAMETER array element may be used anywhere a SIGNED_LONG_INTEGER is legal, with the caveat that it may not be written to.  Array elements are referenced by using the name followed by [element]. The element number may range from 1 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[1], and NUM[2]. The bracket notation is often called an array subscript. NOTE: The [_SKIP_] keyword can be used in INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example:     SIGNED_LONG_INTEGER_PARAMETER temp_level; Specifies one SIGNED_LONG_INTEGER_PARAMETER with the name temp_level in this SIMPL+ program     SIGNED_LONG_INTEGER_PARAMETER CommandBytes[2]; Specifies an array of two SIGNED_LONG_INTEGER_PARAMETERS that can be referenced under the name CommandBytes.  NOTE:  The subscripts of an array may be any positive valid integral expression as shown in the example below.: SIGNED_LONG_INTEGER_PARAMETER location[5], room; SIGNED_LONG_INTEGER var; var = 3; if(room\>0 && room \<= 5) {    print("The location is %d\n", location[var]); } print("The location is %d\n", location[room]); Version: X Generation: Not Supported. 2-Series: SIMPL v2.10.24 or later, CUZ 4.000 or later. [Allowable Ranges for 2 Series Numeric Formats]: ../../Allowable_Ranges_for_2_Series_Numeric_Formats.md [Parameter Property Blocks]: ../Compiler_Directives/PARAMETER_PROPERTIES.md [_SKIP_]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > STRING -------------------------------------------------------------------------------- # STRING Name: STRING Syntax:     STRING \[,\...];     STRING \[,            \...]; Description: Declares a string that is local to this SIMPL+ program. Strings are of arbitrary length, so a maximum size must be specified. When a STRING variable has new data assigned to it, the old data is lost. NOTE:  Strings in Version 3.00 for the 2-Series Control Systems may not be passed by value to a function.  They must be passed by reference. NOTE: If no Return Value is specified within an String_Function, then an empty string will be returned by default. When used in its second form, a one-dimensional array of strings is allocated. The array has num_elements+1 elements, and num_characters per element allocated. The legal indices for referencing the strings are 0 through num_elements. The value of SIZE and NUM_CHARACTER may be up to 255 in SIMPL+ Version 1.00. In SIMPL+ Version 2.00 and later, they may be up to 65534. The value of NUM_ELEMENTS may be up to 65535. NOTE:  (X-Gen) The values of STRINGs declared are non-volatile. If the system is powered down and up, the variables will take on their previous values. If programs are changed and uploaded, the values are not preserved. NOTE:  (2-Series) STRINGs can be volatile or non-volatile. The default is defined using the compiler directives #DEFAULT_NONVOLATILE or #DEFAULT_VOLATILE or overriden using the nonvolatile or volatile keywords. Example:     STRING temp$[10]; Signifies that one local STRING is declared in this SIMPL+ program.     STRING temp$[2][10]; Signifies that three strings of 10 characters long have been allocated. To assign values, the following would be legal:     temp$[0]="Val1";     temp$[1]="Val2";     temp$[2]="Val3"; Version: X Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, SIZE and NUM_CHARACTER up to 65534. 2-Series SIMPL v2.01.05 and later, [Same as X Generation SIMPL v1.50.06] -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > STRING INPUT > STRING_INPUT -------------------------------------------------------------------------------- # STRING_INPUT Name: STRING_INPUT Syntax: STRING_INPUT \[,\...]; STRING_INPUT \; STRING_INPUT \]][max_size]\>; STRING_INPUT \[,[_SKIP_]][,\...]; Description: Routes serial inputs from the outside SIMPL program into a SIMPL+ program under the specified variable names. Strings are of arbitrary length, so a maximum size must be specified. Upon receiving new data, the value is cleared and the new string is put in. Strings received greater than the specified size are truncated to the size in the declaration. String inputs may be written to, so their data space may be used as a storage spot for doing something such as parsing through a string without declaring temporary storage. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  STRING_INPUT variables may not be passed to functions in Version 3.00 for the 2-Series Control Systems. If you need to pass a STRING_INPUT variable to a function, assign it to a locally declared variable and pass that variable to the function. The value of SIZE and NUM_CHARACTER may be up to 255 in SIMPL+ Version 1.00. In SIMPL+ Version 2.00 and later, they may be up to 65535. For an array of STRING_INPUTs, the maximum value of SIZE is 65535. NOTE: \ is the number of inputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: STRING_INPUT FirstName[100], SecondName[25]; Signifies that two serial inputs are coming into the SIMPL+ program from the SIMPL Program. The first one may only be a maximum of 100 characters, the second may only be a maximum of 25 characters. If an input is longer than the specified length, everything after the specified limit is lost. STRING_INPUT DataBaseNames[9][100]; Signifies that 9 serial inputs are coming into the SIMPL+ program from the SIMPL program. Each name has a 100 character limit. The names are referenced as DataBaseNames[1] through DataBaseNames[9]. STRING_INPUT Database Names [9,3][100]; Same as above except at least three are shown at all times Version: X Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, STRING_INPUT arrays and SIZE, NUM_CHARACTER to 65534. 2-Series SIMPL v2.01.05 and later, [Same as X Generation SIMPL v1.50.06] SIMPL v2.03.18 and later, for fixed arrays and minimum sizes. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > STRING OUTPUT > STRING_OUTPUT -------------------------------------------------------------------------------- # STRING_OUTPUT Name: STRING_OUTPUT Syntax: STRING_OUTPUT \[,\...]; STRING_OUTPUT \; STRING_OUTPUT \]][size]\>; STRING_OUTPUT \[,[_SKIP_]][,\...]; Description: Routes serial strings from the SIMPL+ program to the SIMPL program. A string length is not required as the output string buffer management is performed by the operating system. Refer to the discussion on fixed and variable arrays in [Declarations Overview.] NOTE:  These outputs may be jammed with other serial string signals in the SIMPL program, although the value does not propagate back into the SIMPL+ symbol. NOTE: You should use [isSignalDefined] to test whether the output is connected to an actual signal in the SIMPL program before assigning a value to it. If you assign a value and there is no signal, a message is placed in the system error log. NOTE:  The maximum string length for a STRING_OUTPUT is 255 characters. Assigning a string with a length of more than 255 will result in a loss of data. The value of a STRING_OUTPUT cannot be read. If knowledge of the value of the STRING_OUTPUT is required, the value to be written to the STRING_OUTPUT can also be written to a STRING for local storage. In X-Generation Control Systems, if several values are issued to a STRING_OUTPUT, the logic will only see the last value written to the STRING_OUTPUT when the SIMPL+ program task switches away. If all values are required to be seen by the logic, a PROCESSLOGIC statement is required after writing to the STRING_OUTPUT. In the 2-Series Control Systems, all values written to a STRING_OUTPUT are maintained. The logic will see each value of the STRING_OUTPUT. No PROCESSLOGIC is required. For an array of STRING_OUTPUTs, the maximum value of SIZE is 65535. Valid indices are 1 through the specified size. NOTE: \ is the number of outputs shown at a minimum, in SIMPL the default is 1. The user can expand the minimum up to the full size. Only the last array of a type can have a \. NOTE: The [_SKIP_] keyword can be used in DIGITAL_INPUT, DIGITAL_OUTPUT, ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, STRING_INPUT and STRING_OUTPUT declarations. Example: STRING_OUTPUT TheName$; Signifies one string called TheName$ that is generated by the SIMPL+ program and sent to the SIMPL program. STRING_OUTPUT SortedNames$[5]; Specifies five strings that are generated by the SIMPL+ program and sent to the SIMPL program. The names are referred to as SortedNames[1] through SortedNames[5]. STRING_OUTPUT SortedNames$[5,5]; Same as above except all five are always shown. Version: X Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, STRING_OUTPUT Arrays 2-Series SIMPL v2.01.05 and later [Same support as X Generation SIMPL v1.50.06, however, STRING_OUTPUTs or STRING_OUTPUT Arrays cannot be passed by reference] SIMPL v2.03.18 and later, Fixed size arrays and minimum sizes. [_SKIP_]: javascript:void(0); [Declarations Overview.]: Declarations_Overview.md [isSignalDefined]: ../System_Interfacing/IsSignalDefined.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > STRING PARAMETER > STRING_PARAMETER -------------------------------------------------------------------------------- # STRING_PARAMETER Name: STRING_PARAMETER Syntax:     STRING_PARAMETER \[,\...];     STRING_PARAMETER \[,            \...]; Description: The first form declares a STRING_PARAMETER value that is local to this SIMPL+ program.   The second form declares a one dimensional array of STRING_PARAMETER values. The values for SIZE may be up to 65534.  Note that at runtime, the string is truncated to this length if the string specified in SIMPL is longer. The actual value for the parameter is entered as a parameter to the SIMPL+ module when the SIMPL+ module is used the SIMPL program.   STRING_PARAMETERs may have programmatic restrictions placed on them, similar to parameter property sheets for SIMPL modules.  The programmer can allow certain values to be entered, assume default values, among others restrictions.  For more information, please see [Parameter Property Blocks] A STRING_PARAMETER array element may be used anywhere a STRING is legal, with the caveat that it may not be written to.  Array elements are referenced by using the name followed by [element]. The element number may range from 1 to the element size. For example, if an array is declared as NUM[2], then legal elements are NUM[1], and NUM[2]. The bracket notation is often called an array subscript.. NOTE: The [_SKIP_] keyword can be used in INTEGER_PARAMETER, LONG_INTEGER_PARAMETER, SIGNED_INTEGER_PARAMETER, SIGNED_LONG_INTEGER_PARAMETER and STRING_PARAMETER declarations. Example:     STRING_PARAMETER SystemName[10]; Signifies that one local STRING_PARAMETER of 10 bytes wide is declared in this SIMPL+ program and named "SystemName"     STRING_PARAMETER Labels[2][10]; Signifies that two strings of 10 characters long have been allocated and referenced by the array name "Labels".  To reference an element, simply use the [] index notation:     Print("The value of parameter 1 is %s\n", Labels[1]);  Version: X Generation: Not Supported. 2-Series: SIMPL v2.10.24 or later, CUZ 4.000 or later. [Parameter Property Blocks]: ../Compiler_Directives/PARAMETER_PROPERTIES.md [_SKIP_]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > STRUCTURES -------------------------------------------------------------------------------- # STRUCTURES A structure is a collection of one or more variables grouped together under a single name.  These variables, called structure fields or members, may consist of both integer and string datatypes.  Structures help organize related data because they allow variables to be grouped together as a unit instead of as separate entities. Structure datatypes can be defined globally within a SIMPL+ module (\*.usp file) and/or within a SIMPL+ library (\*.usl file).  Variables of a defined structure datatype may be declared both globally and locally and passed as function arguments.  Structures are always passed to functions by reference.  INTEGER, LONG_INTEGER, SIGNED_INTEGER, SIGNED_LONG_INTEGER and STRING are the only SIMPL+ datatypes allowed to be used as structure member fields.  INTEGER and LONG_INTEGER can include 1 and 2 dimensional arrays.  String arrays are not permitted.  The syntax for defining a structure is as follows: STRUCTURE struct_name { type member1; type member2; . . . type memberN; }; The keyword, STRUCTURE, tells the compiler that a new datatype is being defined.  Each type is one of the SIMPL+ datatypes, INTEGER, LONG_INTEGER, SIGNED_INTEGER, SIGNED_LONG_INTEGER or STRING.  struct_name is the name for the structure that will be used as the new datatype. Declaring a variable of a structure datatype is as follows: struct_name var_name; An example of a structure would be an entry in a phone book.  The phone book contains many entries, all containing the same three pieces of information:  the person’s name, address and phone number.  The structure would be defined as follows: STRUCTURE PhoneBookEntry { STRING Name[50]; STRING Address[100]; STRING PhoneNumber[20]; }; PhoneBookEntry OneEntry; PhoneBookEntry Entry[500]; In this example, the name, PhoneBookEntry, is the datatype defined that will encapsulate the structure fields, Name, Address and PhoneNumber.  Two variables are then defined to be of this datatype.  The variable, OneEntry, is a variable that contains one instance of the datatype, PhoneBookEntry.  The variable, Entry, is then defined to be an array of the datatype, PhoneBookEntry consisting of 501 individual instances, namely Entry[0] to Entry[500]. To access a structure’s field, the structure’s declared variable name is used, followed by a period (also known as the ‘dot’ or ‘dot operator’), then followed by a structure member variable name. From the example above, accessing the Name field from the declared variable would be written as follows: OneEntry.Name or Entry[5].Name Using this in a SIMPL+ statement might look as follows: If ( OneEntry.Name = "David" ) Return; If ( Entry[5].Name = "David" ) Return; Passing structures as function arguments is as follows: FUNCTION myFunction ( PhoneBookEntry argOneEntry, PhoneBookEntry argEntry[] ) { if ( argOneEntry.Name = "David" ) return; if ( argEntry[5].Name = "David" ) return; } Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Declarations > VOLATILE > Volatile -------------------------------------------------------------------------------- # Volatile Name: Volatile Syntax:    Volatile NOTE:  This is not a declaration but a declaration modifier. It works only in conjunction with another declaration keyword. Description: Global integer and string program variables will not retain their value if hardware power is lost. Example:     Volatile integer n;     Volatile string s[100]; Version: X Generation:  Not Supported 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > Direct Socket Access Example Code > Direct Socket Access Example Code -------------------------------------------------------------------------------- # Direct Socket Access Example Code #DEFINE_CONSTANT    FALSE        0 #DEFINE_CONSTANT    TRUE         1 //#DEFINE_CONSTANT    INCLUDE_NEW_CODE    1 DIGITAL_INPUT diStartClient; DIGITAL_INPUT diClientReconnectEnable; DIGITAL_INPUT diEnableServer; DIGITAL_INPUT diEnableUDP; ANALOG_INPUT aiClientPortNumber; ANALOG_INPUT aiServerPortNumber; ANALOG_INPUT aiUDP_PortNumber; STRING_INPUT siClientIPAddress[256]; STRING_INPUT siServerIPAddress[256]; STRING_INPUT siUDP_IPAddress[256]; STRING_INPUT siClientTx[256]; STRING_INPUT siServerTx[256]; STRING_INPUT siUDP_Tx[256]; DIGITAL_OUTPUT doClientConnected; DIGITAL_OUTPUT doServerConnected; ANALOG_OUTPUT  aoClientStatus; ANALOG_OUTPUT  aoServerStatus; STRING_OUTPUT  soClientRx; STRING_OUTPUT  soServerRx; STRING_OUTPUT  soUDP_Rx; TCP_CLIENT MyClient[1024]; TCP_SERVER MyServer[1024]; UDP_SOCKET MyUDP[1024]; // Client Example Code PUSH diStartClient {     SIGNED_INTEGER status;     status = SocketConnectClient (MyClient, siClientIPAddress, aiClientPortNumber, diClientReconnectEnable);     if (status \< 0)         Print("Error connecting socket to address %s on port  %d",             SiClientIPAddress, aiClientPortNumber); } RELEASE diStartClient {     SIGNED_INTEGER status;     status = SocketDisconnectClient (MyClient); if (status \< 0)     Print("Error disconnecting socket to address %s on port  %d",             SiClientIPAddress, aiClientPortNumber); } SOCKETCONNECT MyClient {     SIGNED_LONG_INTEGER PortNumber;     SIGNED_INTEGER LocalStatus;     STRING RemoteIPAddress[20];     STRING RequestedAddress[256];     doClientConnected = 1;     LocalStatus = SocketGetAddressAsRequested(MyClient, RequestedAddress);     if (LocalStatus \< 0)         Print("Error getting remote ip address. %d\n", LocalStatus);     Print("OnConnect: Connect call to %s successful\n", RequestedAddress);     PortNumber = SocketGetPortNumber(MyClient);     if (PortNumber \< 0)         Print("Error getting client port number. %ld\n", PortNumber);     LocalStatus = SocketGetRemoteIPAddress(MyClient, RemoteIPAddress);     if (LocalStatus \< 0)         Print("Error getting remote ip address. %d\n", LocalStatus);     Print("OnConnect: Connected to port %ld on address %s\n",                 PortNumber, RemoteIPAddress);     SocketSend(MyClient, "This is sent when the socket starts."); } SOCKETDISCONNECT MyClient {     doClientConnected = 0;     if (diStartClient)         Print("Socket disconnected remotely");     Else         Print("Local disconnect complete."); } SOCKETSTATUS MyClient {     SIGNED_INTEGER Status;     Status = SocketGetStatus();     aoClientStatus = Status;     Print("The SocketGetStatus returns:       %d\n", Status);     Print("The MyClient.SocketStatus returns: %d\n", MyClient.SocketStatus); } SOCKETRECEIVE MyClient {     if (Len(MyClient.SocketRxBuf) \< 256)         Print("Rx: %s", MyClient.SocketRxBuf);     // for now, send to serial output and clear buffer     soClientRx = MyClient.SocketRxBuf;     ClearBuffer(MyClient.SocketRxBuf); } CHANGE siClientTx {     signed_integer iStatus;     iStatus = SocketSend(MyClient, siClientTx );     if (iStatus \< 0)         Print("Error Sending to MyClient: %d\n", iStatus); } // Server Example code PUSH diEnableServer {     SIGNED_INTEGER status;     status = SocketServerStartListen(MyServer, siServerIPAddress, aiServerPortNumber);     if (status \< 0)         Print("Error listening to %s on port %u (status: %d)", siServerIPAddress, aiServerPortNumber, status); } RELEASE diEnableServer {     SIGNED_INTEGER status;     status = SocketServerStopListen(MyServer);     if (status \< 0)         Print("Error stopping server (status: %d)", status); } SOCKETCONNECT MyServer {     SIGNED_INTEGER PortNumber;     doServerConnected = 1;     Print("OnConnect: input buffer size is: %d\n", Len(MyServer.SocketRxBuf));     SocketSend(MyServer, "This is sent when the socket starts."); } SOCKETDISCONNECT MyServer {     doServerConnected = 0;     if (diEnableServer)         Print("Socket disconnected remotely");     Else         Print("Local disconnect complete."); } SOCKETSTATUS MyServer {     SIGNED_INTEGER Status;     Status = SocketGetStatus();     aoServerStatus = Status;     Print("The SocketGetStatus returns:       %d\n", Status);     Print("The MyServer.SocketStatus returns: %d\n", MyServer.SocketStatus); } SOCKETRECEIVE MyServer {     if (Len(MyServer.SocketRxBuf) \< 256)         Print("Rx: %s", MyServer.SocketRxBuf);     // for now, send to serial output and clear buffer     soServerRx = MyServer.SocketRxBuf;     ClearBuffer(MyServer.SocketRxBuf); } CHANGE siServerTx {     signed_integer iStatus;     iStatus = SocketSend(MyServer, siServerTx );     if (iStatus \< 0)         Print("Error Sending to MyServer: %d\n", iStatus); } // UDP Example code PUSH diEnableUDP {     SIGNED_INTEGER status;     status = SocketUDP_Enable(MyUDP, siUDP_IPAddress, aiUDP_PortNumber);     if (status \< 0)         Print("Error listening to %s on port  %d", siUDP_IPAddress, aiUDP_PortNumber); } RELEASE diEnableUDP {     SIGNED_INTEGER status;     status = SocketUDP_Disable (MyUDP);     if (status \< 0)         Print("Error listening on port  %d", aiServerPortNumber); } SOCKETRECEIVE MyUDP {     SIGNED_INTEGER IsBroadcast;     SIGNED_INTEGER IsMulticast;     SIGNED_INTEGER LocalStatus;     STRING SenderIPAddress[32];     IsBroadcast = SocketIsBroadcast(MyUDP);     if (IsBroadcast \< 0)         Print("IsBroadcast returned error: %d\n", IsBroadcast);     IsMulticast = SocketIsMulticast(MyUDP);     if (IsMulticast \< 0)         Print("IsMulticast returned error: %d\n", IsMulticast);     LocalStatus = SocketGetSenderIPAddress(MyUDP, SenderIPAddress);     if (LocalStatus \< 0)         Print("SocketGetSenderIPAddress returned error: %d\n", LocalStatus);     if (IsBroadcast)         Print("Broadcast data received from %s\n", SenderIPAddress);     else if (IsMulticast)         Print("Multicast data received from %s\n", SenderIPAddress);     else         Print("Unicast data received from %s\n", SenderIPAddress);     if (Len(MyUDP.SocketRxBuf) \< 256)         Print("Rx: %s", MyUDP.SocketRxBuf);     // for now, send to serial output and clear buffer     soUDP_Rx = MyUDP.SocketRxBuf;     ClearBuffer(MyUDP.SocketRxBuf); } CHANGE siUDP_Tx {     signed_integer iStatus;     iStatus = SocketSend(MyUDP, siUDP_Tx );     if (iStatus \< 0)         Print("Error Sending to MyUDP: %d\n", iStatus); } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > Direct Socket Access Functions Overview > Direct Socket Access Functions Overview -------------------------------------------------------------------------------- # Direct Socket Access Functions Overview Socket functions make it possible for SIMPL+ to access the Internet, or even simply use Ethernet, without the necessity of going through the SIMPL program. This is important because SIMPL imposes a returned character limit that would truncate a web page or string after about 255 characters. SIMPL+ does not have this limitation so socket functions through SIMPL+ are highly desirable. There are three socket types implemented in SIMPL+ and they are treated as new I/O data types: TCP/IP clients (TCP_CLIENT), TCP/IP server (TCP_SERVER) and UDP socket (UDP_SOCKET). These three sockets each use a pre-defined structure called SOCKET_STRUCT to access the variables and functions in the table later in this topic. NOTE: Declarations of direct socket types must come after all input and output declarations.  The reason for this is that the implied receive buffer for each socket will be indexed starting from the last string or buffer input. The implied structure of client, server and UDP socket SOCKET_STRUCT is shown immediately below.     STRUCTURE SOCKET_STRUCT         {              INTEGER SocketStatus;              STRING  SocketRxBuf;         }TCP_CLIENT, TCP_SERVER, UDP_SOCKET where; Status equals the current status of the socket. The following returned values are comparable to those in the TCP/IP Client and Server symbols: | | | | |-------------------------------|-------|----------------------------| | Keyword | Value | Connection Status | | SOCKET_STATUS_NO_CONNECT | 0 | Not Connected | | SOCKET_STATUS_WAITING | 1 | Waiting for Connection | | SOCKET_STATUS_CONNECTED | 2 | Connected | | SOCKET_STATUS_CONNECT_FAILED | 3 | Connection Failed | | SOCKET_STATUS_BROKEN_REMOTELY | 4 | Connection Broken Remotely | | SOCKET_STATUS_BROKEN_LOCALLY | 5 | Connection Broken Locally | | SOCKET_STATUS_DNS_LOOKUP | 6 | Performing DNS Lookup | | SOCKET_STATUS_DNS_FAILED | 7 | DNS Lookup Failed | | SOCKET_STATUS_DNS_RESOLVED | 8 | DNS Name Resolved | String contains received serial data from the socket. The error codes that can be returned by Direct Socket Access functions are listed in the following table. | | | | |----|----|----| | Keyword | Value | Connection Status | | SOCKET_INVALID_SOCKET       | -1 | Client, Server or UDP variable not a TCP/IP or UDP variable. | | SOCKET_NO_CONNECT_TASK      | -2 | Could not create the connection task | | SOCKET_NO_DNS_RESOLVE       | -3 | Could not resolve address | | SOCKET_INVALID_PORT_NUMBER | -4 | Port not in range of 0-65535. | | SOCKET_NOT_CONNECTED        | -5 | No connection has been established | | SOCKET_STRING_TOO_SMALL     | -6 | Not enough room in string parameter to hold IP address. | The available Direct Socket Functions are described as follows: | | | |----|----| | FUNCTION | DESCRIPTION | | [SocketConnect] | The SocketConnect event is called when a connection is completed on a TCP_CLIENT or  TCP_SERVER variable. | | [SocketDisconnect] | The SocketDisconnect event is called when a TCP_CLIENT or  TCP_SERVER socket is disconnected.   | | [SocketReceive] | The SocketReceive event is called when a TCP_CLIENT or  TCP_SERVER socket receives data. | | [SocketConnectClient] | This function initiates a connection on a TCP_CLIENT socket. | | [SocketDisconnectClient] | This function disconnects a  TCP_CLIENT socket. | | [SocketServerStartListen] | This function initiates listening on a TCP_ SERVER socket. | | [SocketServerStopListen] | This function halts listening on a TCP_SERVER socket. | | [SocketUDP_Enable] | This function enables the operation of an UDP_SOCKET. | | [SocketUDP_Disable] | This function disables the operation of an UDP_SOCKET | | [SocketSend] | This function transmits data on the SOCKET_STRUCT currently being used. SocketSend can be used by all three sockets; TCP_CLIENT, TCP_SERVER and UDP_SOCKET . | | [SocketStatus] | The SocketStatus event is called when the status of a TCP_CLIENT or  TCP_SERVER socket changes. | | [SocketGetStatus] | The SocketGetStatus event is called to retreive the exact status that triggers a SocketStatus event. | | [SocketGetPortNumber] | This function returns the current port number for the given socket.  It is only valid for connected sockets. | | [SocketGetRemoteIPAddress] | This function will return the IP Address of the remote device for a given connection or the IP address of a remote client connected to the given server variable. | | [SocketGetAddressAsRequested] | This function will return the address parameter used for the SocketConnectClient() call or the SocketServerStartListenCall().  It is only valid for connected sockets. | | [SocketIsBroadcast] | This function indicates whether the socket was configured with a broadcast address.  It is only valid for enabled UDP sockets.  This can be used to determine whether a new socket should be created if a unicast response is desired. | | [SocketIsMulticast] | This function indicates whether the socket was configured with a mulitcast address.  It is only valid for enabled UDP sockets.  This can be used to determine whether a new socket should be created if a unicast response is desired. | | [SocketGetSenderIPAddress] | This function returns the IP address of the sender of a UDP.  It is only valid for enabled UDP sockets.  It can only be used in the SOCKETRECEIVE event for a UDP_SOCKET.   | Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [SocketConnect]: SocketConnect.md [SocketDisconnect]: SocketDisconnect.md [SocketReceive]: SocketReceive.md [SocketConnectClient]: SocketConnectClient.md [SocketDisconnectClient]: SocketDisconnectClient.md [SocketServerStartListen]: SocketServerStartListen.md [SocketServerStopListen]: SocketServerStopListen.md [SocketUDP_Enable]: SocketUDP_Enable.md [SocketUDP_Disable]: SocketUDP_Disable.md [SocketSend]: SocketSend.md [SocketStatus]: SocketStatus.md [SocketGetStatus]: SocketGetStatus.md [SocketGetPortNumber]: SocketGetPortNumber.md [SocketGetRemoteIPAddress]: SocketGetRemoteIPAddress.md [SocketGetAddressAsRequested]: SocketGetAddressAsRequested.md [SocketIsBroadcast]: SocketIsBroadcast.md [SocketIsMulticast]: SocketIsMulticast.md [SocketGetSenderIPAddress]: SocketGetSenderIPAddress.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > Direct Socket Error Codes -------------------------------------------------------------------------------- # Direct Socket Error Codes The error codes that can be returned by Direct Socket Access functions are listed in the following table. | | | | |----|----|----| | Keyword | Value | Connection Status | | SOCKET_INVALID_SOCKET       | -1 | Client, Server or UDP variable not a TCP/IP or UDP variable. | | SOCKET_NO_CONNECT_TASK      | -2 | Could not create the connection task | | SOCKET_NO_DNS_RESOLVE       | -3 | Could not resolve address | | SOCKET_INVALID_PORT_NUMBER | -4 | Port not in range of 0-65535. | | SOCKET_NOT_CONNECTED        | -5 | No connection has been established | | SOCKET_STRING_TOO_SMALL     | -6 | Not enough room in string parameter to hold IP address. | | SOCKET_CLIENT_CONNECTED    | -7 | Connecting a client that is already connected. | | SOCKET_CLIENT_CONNECT_IN_PROGRESS    | -8 | Trying to connect a client that is already attempting a connection. | | SOCKET_ETHERNET_NOT_INITIALIZED    | -9 | Trying to connect a client when Ethernet is not fully initialized. | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketConnect -------------------------------------------------------------------------------- # SocketConnect Name: SocketConnect Syntax:     SOCKETCONNECT ClientVariable     {           // user code for routine     } NOTE:  ClientVariable used as an example. ServerVariable also applies. Description: This function is the event function called when a connection is completed on a TCP_CLIENT or  TCP_SERVER variable. The Status field of [SOCKET_STRUCT] holds the [returned values] indicating the status of the connection attempt. (See also [THREADSAFE]) Parameters: ClientVariable: the socket variable declared in the input/output section. ServerVariable: the socket variable declared in the input/output section. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [SOCKET_STRUCT]: Direct_Socket_Access_Functions_Overview.md [returned values]: javascript:void(0); [THREADSAFE]: ../Events/THREADSAFE.md [here]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketConnectClient -------------------------------------------------------------------------------- # SocketConnectClient Name: SocketConnectClient Syntax: SIGNED_INTEGER SocketConnectClient(TCP_CLIENT ClientVariable,STRING Address, INTEGER Port, INTEGER Reconnect); Description: This function initiates a connection on a TCP_CLIENT socket. Parameters: ClientVariable: the socket variable declared in the input/output section. Address: string variable containing the destination address; either as an IP address or as a name to be resolved into an address. Port: number for the TCP client connection. Reconnect: indicates whether the socket should reconnect automatically when disconnected from the remote end. Return Value: 0: Success \<0: Error -1: ClientVariable is not a TCP/IP client variable. -2: Could not create the connection task -3: Port not in range of 0-65535. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketDisconnect > SocketDisconnect: -------------------------------------------------------------------------------- # SocketDisconnect: Name: SocketDisconnect Syntax:     SOCKETDISCONNECT ClientVariable     {           // user code for routine     } NOTE:  ClientVariable used as an example. ServerVariable also applies. Description: The SocketDisconnect event is called when a TCP_CLIENT or  TCP_SERVER socket is disconnected.  The Status field of the [SOCKET_STRUCT] holds the [returned values] indicating the cause of the disconnection. (See also [THREADSAFE]) Parameters: ClientVariable: the socket variable declared in the input/output section. ServerVariable: the socket variable declared in the input/output section. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [SOCKET_STRUCT]: Direct_Socket_Access_Functions_Overview.md [returned values]: Status_Values.md [THREADSAFE]: ../Events/THREADSAFE.md [here]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketDisconnectClient -------------------------------------------------------------------------------- # SocketDisconnectClient Name: SocketDisconnectClient Syntax: SIGNED_INTEGER SocketDisconnectClient (TCP_CLIENT ClientVariable); Description: This function disconnects a TCP_CLIENT socket. Parameters: ClientVariable: the socket variable declared in the input/output section. Return Value: 0: Success \<0: Error -1: ClientVariable is not a TCP/IP client variable. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketGetAddressAsRequested -------------------------------------------------------------------------------- # SocketGetAddressAsRequested Name: SocketGetAddressAsRequested NOTE: This topic covers the SocketGetAddressAsRequested function for TCP_CLIENT ClientVariable and  TCP_SERVER Server Variable. Syntax: SIGNED_INTEGER SocketGetAddressAsRequested (TCP_CLIENT ClientVariable, STRING Address); SIGNED_INTEGER SocketGetAddressAsRequested (TCP_SERVER ServerVariable, STRING Address); Description: This function will return the address parameter used for the SocketConnectClient() call or the SocketServerStartListenCall().  It is only valid for connected sockets. Parameters: For TCP_CLIENT ClientVariable: ClientVariable: the socket variable declared in the input/output section. Address: String variable into which the address is placed. For TCP_SERVER ServerVariable: ServerVariable: the socket variable declared in the input/output section. Address: String variable into which the address is placed. Return Value: 0: Success \<0: Error -1: ClientVariable is not a TCP client variable (TCP_CLIENT ClientVariable). -1: ServerVariable is not a TCP server variable. (TCP_SERVER ServerVariable). -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketGetPortNumber -------------------------------------------------------------------------------- # SocketGetPortNumber Name: SocketGetPortNumber NOTE: This topic covers the SocketGetPortNumber function for TCP_CLIENT ClientVariable, TCP_SERVER Server Variable and UDP_SOCKET UDP_Variable. Syntax: SIGNED_LONG_INTEGER SocketGetPortNumber(TCP_CLIENT ClientVariable); SIGNED_ LONG_INTEGER SocketGetPortNumber(TCP_SERVER ServerVariable); SIGNED_ LONG_INTEGER SocketGetPortNumber(UDP_SOCKET UDP_Variable); Description: This function will return the current port number for the given socket.  It is only valid for connected sockets. Parameters: ClientVariable: the socket variable declared in the input/output section (TCP_CLIENT socket). ServerVariable: the socket variable declared in the input/output section (TCP_SERVER socket). UDP_Variable: the socket variable declared in the input/output section (UDP_SOCKET socket). TxString: String variable containing the data to transmit. Return Value: \>=0: The port number of the current connection. \<0: Error -1: ClientVariable is not a TCP/IP client variable (TCP_CLIENT socket). -1: ServerVariable is not a TCP server variable (TCP_SERVER socket). -1: UDP_Variable is not a UDP variable (UDP_SOCKET socket). -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketGetRemoteIPAddress -------------------------------------------------------------------------------- # SocketGetRemoteIPAddress Name: SocketGetRemoteIPAddress NOTE: This topic covers the SocketGetRemoteIPAddress function for TCP_CLIENT ClientVariable and  TCP_SERVER Server Variable. Syntax: SIGNED_INTEGER SocketGetRemoteIPAddress (TCP_CLIENT ClientVariable, STRING Address); SIGNED_INTEGER SocketGetRemoteIPAddress (TCP_SERVER ServerVariable, STRING Address); Description: This function will return the IP Address of the remote device for a given connection or the IP address of a remote client connected to the given server variable. Parameters: For TCP_CLIENT ClientVariable: ClientVariable: the socket variable declared in the input/output section. Address: String variable into which the address is placed.  The format is the standard dot-decimal notation. For TCP_SERVER ServerVariable: ServerVariable: the socket variable declared in the input/output section. Address: String variable into which the address is placed. Return Value: 0: The Address parameter contains the remote address \<0: Error -1: ClientVariable is not a TCP client variable (TCP_CLIENT ClientVariable). -1: ServerVariable is not a TCP server variable. (TCP_SERVER ServerVariable). -5: No connection has been established -6: Not enough room in string parameter to hold IP address. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketGetSenderIPAddress -------------------------------------------------------------------------------- # SocketGetSenderIPAddress Name: SocketGetSenderIPAddress Syntax: SIGNED_INTEGER SocketGetSenderIPAddress (UDP_SOCKET UDP_Variable, STRING Address); Description: This function returns the IP address of the sender of a UDP.  It is only valid for enabled UDP sockets.  It can only be used in the SOCKETRECEIVE event for a UDP_SOCKET.   Parameters: UDP_Variable: the socket variable declared in the input/output section Address: String variable into which the address is placed. Return Value: 0: Success. \<0: Error -1: UDP_Variable is not a UDP socket variable. -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketGetStatus -------------------------------------------------------------------------------- # SocketGetStatus Name: SocketGetStatus Syntax:    SIGNED_INTEGER SocketGetStatus(); Description: This function is only valid within the SocketStatus event.  The reason this call is needed is to retrieve the exact status that triggered the SocketStatus event.  The status of a socket can change very quickly and if the field in the socket structure is used, interim values could be missed because the code in the SocketStatus routine does not get a chance to run before the structure’s status field changes.  An example of this is when a server socket gets disconnected remotely.  The status will change from connected to disconnected remotely to waiting.  The SocketStatus event will be triggered each time but the status field of the structure may only read waiting even in the broken remotely event. Parameters: None Return Value: The status of the socket when the event was generated. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketIsBroadcast -------------------------------------------------------------------------------- # SocketIsBroadcast Name: SocketIsBroadcast Syntax: SIGNED_INTEGER SocketIsBroadcast (UDP_SOCKET UDP_Variable); Description: This function indicates whether the socket was configured with a broadcast address.  It is only valid for enabled UDP sockets.  This can be used to determine whether a new socket should be created if a unicast response is desired. Parameters: UDP_Variable: the socket variable declared in the input/output section Return Value: 0: The UDP variable is not in a broadcast configuration. 1: The UDP variable is in a broadcast configuration \<0: Error -1:UDP_Variable is not a UDP socket variable. -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketIsMulticast -------------------------------------------------------------------------------- # SocketIsMulticast Name: SocketIsMulticast Syntax: SIGNED_INTEGER SocketIsMulticast (UDP_SOCKET UDP_Variable); Description: This function indicates whether the socket was configured with a mulitcast address.  It is only valid for enabled UDP sockets.  This can be used to determine whether a new socket should be created if a unicast response is desired. Parameters: UDP_Variable: the socket variable declared in the input/output section Return Value: 0: The UDP variable is not in a multicast configuration. 1: The UDP variable is in a multicast configuration \<0: Error -1: UDP_Variable is not a UDP socket variable. -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketReceive -------------------------------------------------------------------------------- # SocketReceive Name: SocketReceive Syntax:     SocketReceive ClientVariable     {           // user code for routine // make sure that the buffer is empty so we can receive new data   ClearBuffer(UDP_Variable.SocketRxBuf);     } NOTE:  ClientVariable used as an example. ServerVariable and UDP_Variable also apply. Description: The RECEIVE event is called when a TCP_CLIENT,  TCP_SERVER or UDP_SOCKET socket receives data.  The Rx$ field of the [SOCKET_STRUCT] contains the data. (See also [THREADSAFE]) NOTE:  The RECEIVE event is comparable to a CHANGE event on the Rx$ field of the socket structure. NOTE: Due to the nature of UDP traffic, each UDP datagram must be processed before the next can be received. For SIMPL+, this means that the buffer must be emptied before the next packet can be received. Please use the ClearBuffer() SIMPL+ routine for this. Parameters: ClientVariable: the socket variable declared in the input/output section. ServerVariable: the socket variable declared in the input/output section. UDP_Variable: the socket variable declared in the input/output section Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [SOCKET_STRUCT]: Direct_Socket_Access_Functions_Overview.md [THREADSAFE]: ../Events/THREADSAFE.md [here]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketSend -------------------------------------------------------------------------------- # SocketSend Name: SocketSend NOTE: This topic covers the SocketGetPortNumber function for TCP_CLIENT ClientVariable, TCP_SERVER Server Variable and UDP_SOCKET UDP_Variable. Syntax: SIGNED_INTEGER SocketSend(TCP_CLIENT ClientVariable, STRING TxString); Description: This function transmits data on the SOCKET_STRUCT currently being used. SocketSend can be used by all three sockets; TCP_CLIENT, TCP_SERVER and UDP_SOCKET. Parameters: ClientVariable: the socket variable declared in the input/output section (TCP_CLIENT socket). ServerVariable: the socket variable declared in the input/output section (TCP_SERVER socket). UDP_Variable: the socket variable declared in the input/output section (UDP_SOCKET socket). TxString: String variable containing the data to transmit. Return Value: \>=0: Success with number of bytes sent (2-series processors) =0: Success (3-series processors) \<0: Error -1: ClientVariable is not a TCP/IP client variable (TCP_CLIENT socket). -1: ServerVariable is not a TCP server variable (TCP_SERVER socket). -1: UDP_Variable is not a UDP variable (UDP_SOCKET socket). -5: No connection has been established NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketServerStartListen -------------------------------------------------------------------------------- # SocketServerStartListen Name: SocketServerStartListen Syntax: SIGNED_INTEGER SocketServerStartListen(TCP_SERVER ServerVariable, STRING Address, INTEGER port); Description: This function initiates listening on a TCP_SERVER socket. Parameters: ServerVariable: the socket variable declared in the input/output section. Address: string variable containing the remote address; either as an IP address or as a name to be resolved into an address.  If non-zero, connections are only allowed from the address matching the string. Port: number for the TCP server connection. Return Value: 0: Success \<0: Error -1: ServerVariable is not a TCP/IP server variable. -4: Port not in range of 0-65535 NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketServerStopListen -------------------------------------------------------------------------------- # SocketServerStopListen Name: SocketServerStopListen Syntax: SIGNED_INTEGER SocketServerStopListen (TCP_SERVER ServerVariable); Description: This function halts listening on a TCP_ SERVER socket. Parameters: ServerVariable: the socket variable declared in the input/output section. Return Value: 0: Success \<0: Error -1: ServerVariable is not a TCP/IP server variable. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketStatus -------------------------------------------------------------------------------- # SocketStatus Name: SocketStatus Syntax:     SOCKETSTATUS ClientVariable     { SIGNED_INTEGER Status;           // user code for routine Status = SocketGetStatus();     } NOTE:  ClientVariable used as an example. ServerVariable also applies. Description: The STATUS event is called when the status of a TCP_CLIENT or  TCP_SERVER socket changes.  Use the SocketGetStatus() routine to retrieve the current status (see [SocketGetStatus]). The Status field of the [SOCKET_STRUCT] holds the [returned values] indicating the current status. NOTE:  The STATUS event is comparable to a CHANGE event on the Status field of the socket structure. (See also [THREADSAFE]) Parameters: ClientVariable: the socket variable declared in the input/output section. ServerVariable: the socket variable declared in the input/output section. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [SocketGetStatus]: javascript:void(0); [SOCKET_STRUCT]: Direct_Socket_Access_Functions_Overview.md [returned values]: Status_Values.md [THREADSAFE]: ../Events/THREADSAFE.md [here]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketUDP Disable > SocketUDP_Disable -------------------------------------------------------------------------------- # SocketUDP_Disable Name: SocketUDP_Disable Syntax: SIGNED_INTEGER SocketUDP_Disable(UDP_SOCKET UDP_Variable); Description: This function disables the operation of an UDP_SOCKET. Parameters: UDP_Variable: the socket variable declared in the input/output section. Return Value: 0: Success \<0: Error -1: UDP_Variable is not a UDP variable. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > SocketUDP Enable > SocketUDP_Enable -------------------------------------------------------------------------------- # SocketUDP_Enable Name: SocketUDP_Enable Syntax: SIGNED_INTEGER SocketUDP_Enable(UDP_SOCKET UDP_Variable, STRING address,  INTEGER port); Description: This function enables the operation of an UDP_SOCKET. Parameters: UDP_Variable: the socket variable declared in the input/output section. Address: string variable containing the remote address; either as an IP address or as a name to be resolved into an address Port: port number to use for communications. Return Value: 0: Success \<0: Error -1: UDP_Variable is not a UDP variable. -3: Could not resolve address -4: Port not in range of 0-65535. NOTE: Return values that are negative numbers are errors. More information on error codes for Direct Socket functions can be found [here]. Example: In the case of Direct Socket Access Functions and events, the example code is best when viewed in the context in which it applies. For that reason, the example code for this event can be viewed by clicking [here][1]. A scrolling pop up will open for your convenience. Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later [here]: javascript:void(0); [1]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Direct Socket Access > Status Values -------------------------------------------------------------------------------- # Status Values The returned Status values of TCP_CLIENT, TCP_SERVER, and UDP_SOCKET  connections can be found in the following table. | | | | |-------------------------------|-------|----------------------------| | Keyword | Value | Connection Status | | SOCKET_STATUS_NO_CONNECT | 0 | Not Connected | | SOCKET_STATUS_WAITING | 1 | Waiting for Connection | | SOCKET_STATUS_CONNECTED | 2 | Connected | | SOCKET_STATUS_CONNECT_FAILED | 3 | Connection Failed | | SOCKET_STATUS_BROKEN_REMOTELY | 4 | Connection Broken Remotely | | SOCKET_STATUS_BROKEN_LOCALLY | 5 | Connection Broken Locally | | SOCKET_STATUS_DNS_LOOKUP | 6 | Performing DNS Lookup | | SOCKET_STATUS_DNS_FAILED | 7 | DNS Lookup Failed | | SOCKET_STATUS_DNS_RESOLVED | 8 | DNS Name Resolved | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Email Functions > Email Function Return Error Codes > Email Function Return Error Codes -------------------------------------------------------------------------------- # Email Function Return Error Codes | SMTP_OK | 0 | Success | | ------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------- | | SMTP ERRORS (NON-RECOVERABLE ERRORS) | | | | Error | Description | | | SMTP_ERROR_FATAL | -1 | Any non-recoverable error from the e-mail module of the firmware (for example: if “mailserver”, “from” and “to” are empty). | | SMTP_ERROR_ILLEGAL_CMD | -2 | General internal error. | | SMTP_ERROR_CONNECT | -3 | Failure to connect to the mailserver. | | SMTP_ERROR_SEND | -4 | Internal error while actually sending out e-mail. | | SMTP_ERROR_RECV | -5 | Internal error while actually receiving out e-mail. | | SMTP_ERROR_NU_CONNECT | -6 | Internal error while processing the send. | | SMTP_ERROR_NU_BUFFERS | -7 | Lack of memory buffers while processing send or receive mail. Internal error. | | SMTP_ERROR_AUTHENTICATION | -8 | Authentication failure. | | SMTP_ERROR_AUTH_LOGIN_UNSUPPORTED | -9 | CLEAR TEXT login scheme is not supported. | | SMTP_INV_PARAM | -10 | Bad parameters to SendMail. Must supply Server, From, and To. | | SMTP_ETHER_NOT_ENABLED | -11 | Ethernet not enabled. Cannot send mail. | | SMTP_NO_SERVER_ADDRESS | -12 | No DNS servers configured. Cannot resolve name. | | SMTP_SEND_FAILURE | -13 | SendMail failed. | | SMTP FAILURES (RECOVERABLE ERRORS) | | | | Error | Description | | | IDS_SMTP_FAILURE_MAIL_COMMAND | 2 | There was an error sending e-mail with the "from" recipient. | | SMTP_FAILURE_TO_RCPT_COMMAND | 3 | There was an error sending e-mail to the “to” recipient. | | SMTP_FAILURE_CC_RCPT_COMMAND | 4 | There was an error sending e-mail to the “CC” recipient. | | SMTP_FAILURE_DATA_COMMAND | 5 | There was an error sending the message body. | | SMTP_FAILURE_ATTACHMENT_OPEN | 6 | Unable to open attachment file | [Related Topics Link IconRelated Topics] [Related Topics Link IconRelated Topics]: javascript:mc1.Click() -------------------------------------------------------------------------------- ## Language Constructs & Functions > Email Functions > Important SendMail Considerations -------------------------------------------------------------------------------- # Important SendMail Considerations 1. In the SIMPL+ function call to "Send Mail", the parameters "Mailserv", "To" and "From" fields are MANDATORY, whereas "cc", "subject" and "message" are not. 2. Only the "SMTP AUTH" authentication type with "LOGIN" authentication scheme is supported for now. 3. Questions for the ISP/e-mail service provider to determine compatibility with the SEND MAIL feature.\   - Does the ISP/service provider support NON-WEB clients? - Does the ISP/service provider support "SMTP AUTH" authentication type with "LOGIN" authentication scheme? - For example: the e-mail provider SBC YAHOO supports web as well as non web clients. For non web clients, one of the mail servers to communicate with is SMTPAUTH.FLASH.NET. This mail server supports SMTP AUTH and LOGIN auth scheme. 4. SEND MAIL client queries the mail server to determine the authentication type and scheme and returns an "unsupported" error (error # -9) if the mail-server does not support LOGIN scheme; however if the client is unable to determine information regarding the schemes supported, it will go ahead and try to send out the e-mail to the intended recipients, but the server may refuse to relay it to external destinations. This will return a "failure" code. (Refer to [Email Function Return Error Codes] ) 5. For mail servers needing no authentication, the "username" and "password" field are set to an EMPTY STRING (""). Again, as in (4) above there is no guarantee that the mail-server will relay the e-mail to external destinations. 6. In case of an error/failure, the first occurring error/failure code is returned. 7. If the message line exceeds 998 characters without a \ sequence, the SEND MAIL module automatically inserts one. 8. The "Mail-server" parameter in the SIMPL+ function call to Send Mail can be an IP address, ex. "132.149.6.220" or a name "mail1.Mycompanyname.com". In case of a name, DNS will be used to resolve the name, and the control system must have a DNS server set up. 9. REMINDER: Strings in SIMPL+ can only be 256 characters long. But internal to SIMPL+ they can be concatenated to a total length of 65536 characters, as long as a SIMPL+ BUFFER_INPUT type is used to accumulate the strings. [Email Function Return Error Codes]: Email_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Email Functions > SendMail > SendMail -------------------------------------------------------------------------------- # SendMail Name: SendMail Syntax:     SIGNED_INTEGER SendMail( STRING Server,                      STRING UserLogonName,                      STRING UserLogonPassword,                      STRING From,                      STRING To,                      STRING CC,                      STRING Subject,                      STRING Message       ) Description: Send an email message using SMTP protocol. Parameters: Server - Required.  Specifies address of the mail server.  It can either be an IP address in dot-decimal notation (ex: 192.168.16.3) or a name to be resolved with a DNS server (ex:  mail.myisp.com).  If a name is given, the control system must be configured with a DNS server (ADDDNS console command).   Maximum field length: 40. UserLogonName - Optional, but use an empty string in its place if authentication is not required.   If the mail server requires authentication, UserLogonName indicates the user name of the sender for the mail server.   An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. UserLogonPassword - Optional, but put an empty string in it's place if not required.   If the mail server requires authentication, UserLogonPassword indicates the password of the sender for the mail server.  An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. From -  Required.  Specifies the e-mail address of the sender in the a@b.com format.  Only one email address is allowed.  Aliases or nicknames are not supported.  This argument is mandatory.  Maximum field length: 242. To - Required.  Specifies the e-mail address of the recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  This argument is mandatory.  Maximum field length: 65535. CC - Optional, but use an empty string to indicate that there are no recipients.  Specifies the e-mail address of the carbon copy recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  Maximum field length: 65535. Subject - Optional, but use an empty string to indicate that there is no subject.  Specifies the subject of the email message.  Maximum field length: 989. Message - Optional, but use an empty string to indicate an empty message.  Specifies the body of the email message.    Maximum field length: 65535. Return Value: 0 if successful.   Otherwise,  [Email Return Error Code] is returned. Negative return error codes indicate that no part of the email was sent (example:  user logon password was incorrect).  Positive return error codes indicate a failure (example: one or more recipient email addresses was invalid), but the email was still sent.  In the event of more than one failure, the return error code of the first failure is returned. Example:          SIGNED_INTEGER nErr;     nErr = SendMail( "192.168.16.3",                      "UserLogonName",                      "UserLogonPassword",                                         "SenderEmailAddress@crestron.com",                      "RecipientEmailAddress@crestron.com",                      "ccEmailAddress@crestron.com",                      "This is the subject",                      "This is the message" );    if ( nErr \< 0 )                Print( "Error sending email\n" );    else                Print( "SendMail successful!\n ); Version: X Generation:  Not Supported 2-Series:  SIMPL v2.03.18 and later [Email Return Error Code]: Email_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Email Functions > SendMailAdvance > SendMailAdvance -------------------------------------------------------------------------------- # SendMailAdvance Name: SendMailAdvance Syntax: SIGNED_INTEGER SendMailAdvance( STRING Server, INTEGER PortNumber STRING UserLogonName, STRING UserLogonPassword, STRING From, STRING To, STRING CC, STRING Subject, STRING Message, INTEGER NumberOfAttachments, STRING Attachment ) Description: Programatically sends an email message to the specified IP address on the specified port using the SMTP protocol. Parameters: Server - Required.  Specifies address of the mail server.  It can either be an IP address in dot-decimal notation (ex: 192.168.16.3) or a name to be resolved with a DNS server (ex:  mail.myisp.com).  If a name is given, the control system must be configured with a DNS server (ADDDNS console command).   Maximum field length: 40. PortNumber - Required. Specifies the port number used to send the email. UserLogonName - Optional.  Use an empty string in its place if authentication is not required.   If the mail server requires authentication, UserLogonName indicates the user name of the sender for the mail server.   An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. UserLogonPassword - Optional.  Use an empty string in it's place if not required.   If the mail server requires authentication, UserLogonPassword indicates the password of the sender for the mail server.  An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. From -  Required.  Specifies the e-mail address of the sender in the a@b.com format.  Only one email address is allowed.  Aliases or nicknames are not supported.  This argument is mandatory.  Maximum field length: 242. To - Required.  Specifies the e-mail address of the recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  This argument is mandatory.  Maximum field length: 65535. CC - Optional.  An empty string indicates that there are no recipients.  Specifies the e-mail address of the carbon copy recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  Maximum field length: 65535. Subject - Optional.  An empty string indicates that there is no subject.  Specifies the subject of the email message.  Maximum field length: 989. Message - Optional.  An empty string indicates an empty message.  Specifies the body of the email message.    Maximum field length: 65535. NumberOfAttachments - Optional.  0 specifies that there are no attachments.  Specifies the number of attachments to be sent. Attachment - Optional.  An empty string indicates that no attachments are to be sent.  Specifies the files to be attached. Multiple filenames may be specified, delimited by ';'. Max field length is 65534. Return Value: 0 if successful.   Otherwise,  Email Return [Error Code] is returned. Negative return [error codes][Error Code] indicate that no part of the email was sent (example:  user logon password was incorrect).  Positive return [error codes][Error Code] indicate a failure (example: one or more recipient email addresses was invalid), but the email was still sent.  In the event of more than one failure, the return [error code] of the first failure is returned. Example: SIGNED_INTEGER nErr;     nErr = SendMailAdvance( "192.168.16.3",  80 "UserLogonName", "UserLogonPassword",                    "SenderEmailAddress@crestron.com", "RecipientEmailAddress@crestron.com", "ccEmailAddress@crestron.com", "This is the subject", "This is the message", 2, "\\CF0\\test.pdf;\\CF0\\test.img" );    if ( nErr \< 0 )                Print( "Error sending email\n" );    else                Print( "SendMail successful!\n ); NOTE: If the attachment count is 0 but the "attachment" parameter is not empty, OR if the attachment count is positive, but the "attachment" parameter is empty, an SMTP_INV_PARM error will be returned with the following error in the error log, ""Bad Attachment parameters to SendMail". \ \ NOTE: If the attachment count does not match the number of files in the "attachment" parameter (separated by a delimiter) then the following will happen.  If the attachment count parameter is less than the number of files specified in the "attachment" parameter, then the function will attempt to send out valid files specified by the attachment count parameter(INTEGER).\ \ NOTE: If the attachment count parameter is more than the number of files specified in the "attachment" parameter, then the function will attempt to send the valid files specified by the "attachment" parameter(STRING).  Version: X Generation:  Not Supported 2-Series:  SIMPL v2.05.17 and later. CUZ 4.001 or later. [Error Code]: Email_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Email Functions > SendMailWithAttachments > SendMailWithAttachments -------------------------------------------------------------------------------- # SendMailWithAttachments Name: SendMailWithAttachments Syntax: SIGNED_INTEGER SendMailWithAttachments( STRING Server, STRING UserLogonName, STRING UserLogonPassword, STRING From, STRING To, STRING CC, STRING Subject, STRING Message, INTEGER NumberOfAttachments, STRING Attachment ) Description: Send an email message with attachments using SMTP protocol. Parameters: Server - Required.  Specifies address of the mail server.  It can either be an IP address in dot-decimal notation (ex: 192.168.16.3) or a name to be resolved with a DNS server (ex:  mail.myisp.com).  If a name is given, the control system must be configured with a DNS server (ADDDNS console command).   Maximum field length: 40. UserLogonName - Optional.  Use an empty string in its place if authentication is not required.   If the mail server requires authentication, UserLogonName indicates the user name of the sender for the mail server.   An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. UserLogonPassword - Optional.  Use an empty string in it's place if not required.   If the mail server requires authentication, UserLogonPassword indicates the password of the sender for the mail server.  An empty string indicates that authentication is not required.  Only "clear text" authentication is implemented. "Clear text" refers to the authentication method used by the mail server. If the mail server requires a higher level authentication, mail can not be sent to the mail server.  Maximum field length: 254. From -  Required.  Specifies the e-mail address of the sender in the a@b.com format.  Only one email address is allowed.  Aliases or nicknames are not supported.  This argument is mandatory.  Maximum field length: 242. To - Required.  Specifies the e-mail address of the recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  This argument is mandatory.  Maximum field length: 65535. CC - Optional.  An empty string indicates that there are no recipients.  Specifies the e-mail address of the carbon copy recipient(s) in the a@b.com format.  Multiple recipients may be specified delimited with a ";".  Maximum field length: 65535. Subject - Optional.  An empty string indicates that there is no subject.  Specifies the subject of the email message.  Maximum field length: 989. Message - Optional.  An empty string indicates an empty message.  Specifies the body of the email message.    Maximum field length: 65535. NumberOfAttachments - Optional.  0 specifies that there are no attachments.  Specifies the number of attachments to be sent. Attachment - Optional.  An empty string indicates that no attachments are to be sent.  Specifies the files to be attached. Multiple filenames may be specified, delimited by ';'. Max field length is 65534. Return Value: 0 if successful.   Otherwise,  Email Return [Error Code] is returned. Negative return [error codes][Error Code] indicate that no part of the email was sent (example:  user logon password was incorrect).  Positive return [error codes][Error Code] indicate a failure (example: one or more recipient email addresses was invalid), but the email was still sent.  In the event of more than one failure, the return [error code] of the first failure is returned. Example: SIGNED_INTEGER nErr;     nErr = SendMailWithAttachments( "192.168.16.3", "UserLogonName", "UserLogonPassword",                    "SenderEmailAddress@crestron.com", "RecipientEmailAddress@crestron.com", "ccEmailAddress@crestron.com", "This is the subject", "This is the message", 2, "\\CF0\\test.pdf;\\CF0\\test.img" );    if ( nErr \< 0 )                Print( "Error sending email\n" );    else                Print( "SendMail successful!\n ); NOTE: If the attachment count is 0 but the "attachment" parameter is not empty, OR if the attachment count is positive, but the "attachment" parameter is empty, an SMTP_INV_PARM error will be returned with the following error in the error log, ""Bad Attachment parameters to SendMail". \ \ NOTE: If the attachment count does not match the number of files in the "attachment" parameter (separated by a delimiter) then the following will happen.  If the attachment count parameter is less than the number of files specified in the "attachment" parameter, then the function will attempt to send out valid files specified by the attachment count parameter(INTEGER).\ \ NOTE: If the attachment count parameter is more than the number of files specified in the "attachment" parameter, then the function will attempt to send the valid files specified by the "attachment" parameter(STRING).  Version: X Generation:  Not Supported 2-Series:  SIMPL v2.05.17 and later [Error Code]: Email_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ASCII -------------------------------------------------------------------------------- # ASCII Name: ASCII Syntax:     ASCII NOTE: This is not a declaration but a declaration modifier. It works only in conjunction with the STRING declaration keyword.    Description: The encoding of the string will be forced to ASCII if the declaration is preceded by the ASCII modifier. Example:  ASCII string s[100]; Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > GETENCODING > GetEncoding -------------------------------------------------------------------------------- # GetEncoding Name: GetEncoding Syntax:     GetEncoding(STRING myString); Description: Returns the encoding of a string. The following constants are declared to help comparison: ENCODING_ASCII – Returned when the encoding of the string is set to ASCII. ENCODING_UTF16 – Returned when the encoding of the string is set to [UTF16]. Any other return value should be treated as an error. Parameters: myString is a string declared in the program. This can either be a global string or a local string. Return Value: An INTEGER containing the encoding of the string. The value of the return value can either be ASCII or UTF16. Example:    In this example, the string encoding is retrieved from a string an appropriate string is printed on the console. Function GetEncodingFunction() {    INTEGER encoding;    STRING  myString[10];    encoding = getencoding(myString);    if (encoding = ENCODING_ASCII)      print ("ASCII\r\n");    else if (encoding = ENCODING_UTF16)      print ("UTF16\r\n");    else      print ("Error getting encoding\r\n"); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported [UTF16]: UTF16_Unicode_Encoding.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > Inherit > INHERIT -------------------------------------------------------------------------------- # INHERIT Name: INHERIT Syntax:     INHERIT NOTE: This is not a declaration but a declaration modifier. It works only in conjunction with the STRING declaration keyword.    Description: The encoding of the string will be forced to the module’s default inherited encoding type.  Inherited encoding types can either be from the parent module or calling program.  These are both set by the compiler directives, [#ENCODING_INHERIT_FROM_PARENT] and [#ENCODING_INHERIT_FROM_PROGRAM]. Example:  INHERIT string s[100]; Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [#ENCODING_INHERIT_FROM_PARENT]: _ENCODING_INHERIT_FROM_PARENT.md [#ENCODING_INHERIT_FROM_PROGRAM]: _ENCODING_INHERIT_FROM_PROGRAM.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > SetEncoding -------------------------------------------------------------------------------- # SetEncoding Name: SetEncoding Syntax:     SetEncoding(STRING myString, ENCODING_TYPE encoding); Description: Sets the encoding of a string. Encoding can only be one the following types: ENCODING_ASCII – Encoding of the string is set to ASCII. ENCODING_UTF16 – Encoding of the string is set to [UTF16]. ENCODING_INHERIT – Encoding of the string is set to the inherited encoding of the module. The encoding directive is used to set the encoding. Parameters: myString is a string declared in the program. This can either be a global string or a local string. Encoding can either be ENCODING_ASCII, ENCODING_UTF16 or ENCODING_INHERIT. Return Value: None. Example:    In this example, the string encoding is set on a string. Function SetEncodingFunction() {    STRING  myString[10];    // Set encoding to ASCII    setencoding(myString, ENCODING_ASCII);    // Set encoding to UTF16    setencoding(myString, ENCODING_UTF16);    // Set encoding to default encoding inherited using the encoding directive.    setencoding(myString, ENCODING_INHERIT); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported [UTF16]: UTF16_Unicode_Encoding.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ToASCII > ToASCII() -------------------------------------------------------------------------------- # ToASCII() Name: ToASCII Syntax:     STRING ToASCII(STRING myString);   Description: Converts the encoding of a [UTF16] string to ASCII. Parameters: myString is a string declared in the program. This can either be a global string or a local string. Return Value: A reference to myString after conversion. Example:    In this example, the string encoding is converted to ASCII. Function ConvertEncodingToASCII() {   UTF16 STRING utf16String[10];   INTEGER encoding;   TOASCII(utf16String);   encoding = getencoding(utf16String);   if (encoding = ENCODING_ASCII)     print ("ASCII\r\n");   else if (encoding = ENCODING_UTF16)     print ("UTF16\r\n");   else     print ("Error getting encoding\r\n"); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported [UTF16]: UTF16_Unicode_Encoding.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ToUTF16 -------------------------------------------------------------------------------- # ToUTF16 Name: ToUTF16 Syntax:     STRING ToUTF16 (STRING myString);    Description: Converts the encoding of the string to [UTF16]. Parameters: myString is a string declared in the program. This can either be a global string or a local string. Return Value: A reference to myString after conversion. Example:  In this example, the string encoding is converted to UTF16. Function ConvertEncodingToUTF16() {   ASCII STRING ascString[10];   INTEGER encoding;   TOUTF16(ascString);   encoding = getencoding(ascString);   if (encoding = ENCODING_ASCII)     print ("ASCII\r\n");   else if (encoding = ENCODING_UTF16)     print ("UTF16\r\n");   else     print ("Error getting encoding\r\n"); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported [UTF16]: UTF16_Unicode_Encoding.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > UTF16 -------------------------------------------------------------------------------- # UTF16 Name: UTF16 Syntax:     UTF16 NOTE: This is not a declaration but a declaration modifier. It works only in conjunction with the STRING declaration keyword.    Description: The encoding of the string will be forced to UTF16 if the declaration is preceded by the UTF16 modifier. Example:  UTF16 string s[100]; Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > UTF16 Unicode Encoding -------------------------------------------------------------------------------- # UTF16 Unicode Encoding Systems may either be ASCII compliant or use Unicode. Unicode allows for characters that are greater than 8 bits, which means that character sets other than the standard US character sets may be used.  Typically this would be for talking to a touch screen using other character sets (Chinese, Japanese, etc.) In Unicode terminology, it is commonplace to express a character in terms of a “Codepoint”.  This allows someone to reference a particular character without worrying about the underlying encoding mechanism.   A codepoint is specified as U+{4 digits} or U+{6 digits}. In the 2 series, strings are encoded as a series of bytes, and so there is no concept of encoding for Unicode.   In the 3 series, strings are encoded as a series of words. Therefore a string expressed in SIMPL as “\x25\x26\x27” is actually stored as 3 words; 0x0025, 0x0026, and 0x0027. Since the system deals with bytes at the lowest level, Crestron has decided to encode as in a format known as “Little Endian” – which is the Low byte of a word followed by the High byte of a word.   The actual storage on a byte level is 0x26 0x00 0x26 0x00 0x27 0x00. NOTE: A word is another name for a 16b value, much like a byte is a name for an 8b value. In the 3 Series, Crestron has chosen to use UTF-16LE as our particular encoding method for Unicode.  LE stands for Little Endian to reflect the above storage concept. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ENCODING ASCII > #ENCODING_ASCII -------------------------------------------------------------------------------- # #ENCODING_ASCII Name: #ENCODING_ASCII Syntax:     #ENCODING_ASCII Description: An encoding directive is used to indicate the default encoding of strings if the encoding is not specified by an encoding keyword. The #ENCODING_ASCII directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with ASCII encoding. NOTE: If an encoding directive is not specified in a file, all strings will default to ASCII encoding. Example:    #ENCODING_ASCII Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ENCODING INHERIT FROM PARENT > #ENCODING_INHERIT_FROM_PARENT -------------------------------------------------------------------------------- # #ENCODING_INHERIT_FROM_PARENT Name: #ENCODING_INHERIT_FROM_PARENT Syntax:     #ENCODING_INHERIT_FROM_PARENT Description: An encoding directive is used to indicate the default encoding of strings if the encoding is not specified by an encoding keyword. The #ENCODING_INHERIT_FROM_PARENT directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with default encoding of the parent of this module. NOTE: If an encoding directive is not specified in a file, all strings will default to ASCII encoding. Example:    #ENCODING_INHERIT_FROM_PARENT Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ENCODING INHERIT FROM PROGRAM > #ENCODING_INHERIT_FROM_PROGRAM -------------------------------------------------------------------------------- # #ENCODING_INHERIT_FROM_PROGRAM Name: #ENCODING_INHERIT_FROM_PROGRAM Syntax:     #ENCODING_INHERIT_FROM_PROGRAM Description: An encoding directive is used to indicate the default encoding of strings if the encoding is not specified by an encoding keyword. The #ENCODING_INHERIT_FROM_PROGRAM directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with default encoding of the parent of this module. NOTE: If an encoding directive is not specified in a file, all strings will default to ASCII encoding. Example:    #ENCODING_INHERIT_FROM_PROGRAM Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > ENCODING UTF16 > #ENCODING_UTF16 -------------------------------------------------------------------------------- # #ENCODING_UTF16 Name: # ENCODING_UTF16 Syntax:     #ENCODING_UTF16 Description: An encoding directive is used to indicate the default encoding of strings if the encoding is not specified by an encoding keyword. The #ENCODING_UTF16 directive will ensure that any strings in the SIMPL+ module without explicit encoding keywords are marked with [UTF16] encoding. NOTE: If an encoding directive is not specified in a file, all strings will default to ASCII encoding. Example:    #ENCODING_UTF16 Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: Supported 4-Series: Supported [UTF16]: UTF16_Unicode_Encoding.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > IF SERIES2 > #IF_SERIES2 -------------------------------------------------------------------------------- # #IF_SERIES2 Name: # IF_SERIES2 Syntax:     #IF_SERIES2 \ [ #ELSE \ ] #ENDIF Description: When compiling for different control system targets, it might be desirable to have each target execute a different portion of code.  Reasons for this might be new or obsolete functions or different performance characteristics in each control system. Using this compiler directive will cause the compiler to only include the statements for the 2-series control system.  The #ELSE block is optional and may be used if a different set of code should be executed when the 2-series is not the target control system. Example:    #IF_SERIES2 Function FunctionOne() { } #ENDIF #IF_SERIES2 Function FunctionTwo() { } #ELSE Function FunctionThree() { } #ENDIF Function FunctionFour() { #IF_SERIES2 // some code #ELSE // some other code #ENDIF } Version: X Generation:  Not Supported 2-Series:   3-Series: -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > IF SERIES3 > #IF_SERIES3 -------------------------------------------------------------------------------- # #IF_SERIES3 Name: # IF_SERIES3 Syntax:     #IF_SERIES3 \ [ #ELSE \ ] #ENDIF Description: When compiling for different control system targets, it might be desirable to have each target execute a different portion of code.  Reasons for this might be new or obsolete functions or different performance characteristics in each control system. Using this compiler directive will cause the compiler to only include the statements for the 3-series control system.  The #ELSE block is optional and may be used if a different set of code should be executed when the 3-series is not the target control system. NOTE: During a compilation for 4-series control systems SIMPL will issue a warning whenever a #IF_SERIES3 directive is found.\ \ As any logic contained in the #IF_SERIES3 block WILL NOT be compiled for 4-series control systems make sure that logic intended for 4-series control system is outside of the #IF_SERIES3 block.\ Example:    #IF_SERIES3 Function FunctionOne() { } #ENDIF #IF_SERIES3 Function FunctionTwo() { } #ELSE Function FunctionThree() { } #ENDIF Function FunctionFour() { #IF_SERIES3 // some code #ELSE // some other code #ENDIF } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Encoding > IF SERIES4 > #IF_SERIES4 -------------------------------------------------------------------------------- # #IF_SERIES4 Name: # IF_SERIES4 Syntax:     #IF_SERIES4 \ [ #ELSE \ ] #ENDIF Description: When compiling for different control system targets, it might be desirable to have each target execute a different portion of code.  Reasons for this might be new or obsolete functions or different performance characteristics in each control system. Using this compiler directive will cause the compiler to only include the statements for the 4-series control system.  The #ELSE block is optional and may be used if a different set of code should be executed when the 4-series is not the target control system. The #IF_SERIES4 keyword is ignored and the SIMPL+ module should compile without issues when the SIMPL+ module target control system class is any of the following: - 2-Series only - 3-Series only - 2-Series and 3-Series Example:    #IF_SERIES4 Function FunctionOne() { } #ENDIF #IF_SERIES4 Function FunctionTwo() { } #ELSE Function FunctionThree() { } #ENDIF Function FunctionFour() { #IF_SERIES4 // some code #ELSE // some other code #ENDIF } Version: 4-Series: SIMPL v. 4.14.xx -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > CHANGE -------------------------------------------------------------------------------- # CHANGE Name: CHANGE Syntax:     CHANGE \ [, \ ...]     {       [Local Variable Definitions]       \     } Description: The CHANGE event is called when a DIGITAL_INPUT transitions from low to high or high to low, or when an ANALOG_INPUT or STRING_INPUT changes. \ may be either a DIGITAL_INPUT, ANALOG_INPUT, or STRING_INPUT  type. If it is a DIGITAL_INPUT, the statements between { and } will be executed when the input transitions from low to high or high to low. If it is an ANALOG_INPUT or STRING_INPUT, the statements between { and } will be executed whenever the variable changes. Note that for an ANALOG_INPUT or STRING_INPUT, the same value re-issued will also cause the CHANGE to activate. When using ANALOG_INPUT, BUFFER_INPUT, DIGITAL_INPUT, or STRING_INPUT arrays, only a change in the entire array can be detected, not an individual element. Refer to "[GetLastModifiedArrayIndex]" to determine which element actually changed. Use isSignalDefined to make sure that you send data only to outputs that exist or take input from signals that exist. When listing multiple variable names, the names can be put on the same line or broken up into several CHANGE statements for readability. (See also [StackedEvents] and [THREADSAFE]) Example:     STRING_INPUT some_data$[100];     ANALOG_OUTPUT level;     CHANGE some_data$     {       level=48;     } When the STRING_INPUT changes, the ANALOG_OUTPUT level will have the value 48 put into it. If the same data comes in on some_data$, the CHANGE block is executed again.     ANALOG_INPUT ThingsToAdd[20];     ANALOG_OUTPUT Sum;     INTEGER I, Total;     CHANGE ThingsToAdd     {       Total=0;       FOR(I=0 to 20) if (isSignalDefined (ThingsToAdd[I]))         Total = Total + ThingsToAdd[I];       Sum = Total;     } In this example, an array is used to hold elements to add. When any element of the array changes, the total is recomputed and issued on an analog output variable. Version: X Generation: SIMPL v1.20.01 and later SIMPL v1.50.06 and later, ANALOG_INPUT, BUFFER_INPUT, DIGITAL_INPUT, and STRING_INPUT arrays as \ 2-Series: SIMPL v2.01.05 and later [Same as X Generation SIMPL v1.50.06] and Local Variables allowed within CHANGE statements. [GetLastModifiedArrayIndex]: ../Array_Operations/GetLastModifiedArrayIndex.md [StackedEvents]: Stacked_Events.md [THREADSAFE]: THREADSAFE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > EVENT -------------------------------------------------------------------------------- # EVENT Name: EVENT Syntax:     EVENT     {       [Local Variable Definitions]       \     } Description: Executes the defined \ anytime one of the inputs to the SIMPL+ symbol changes. It is similar to having a CHANGE statement listed for every input, and each change is set up to execute a common block of code. (see also [StackedEvents] and [THREADSAFE]) Example:     ANALOG_INPUT level1, level2, level3;     STRING_INPUT extra$[2][20];     STRING_OUTPUT OUT$;     EVENT     {       OUT$=extra$[0]+extra$[1]+CHR(level1)+CHR(level2)+CHR(level3);     } In this example, when the ANALOG_INPUTs level1, level2, level3, or level4 have any change or the STRING_INPUT array extra$ has changed, the STRING_OUTPUT OUT$ will be recomputed and reissued. Version: X Generation: SIMPL v1.20.01 and later 2-Series SIMPL v2.01.05 and later [Same as X Generation v1.20.01], however Local variables are allowed within EVENT statements. [StackedEvents]: Stacked_Events.md [THREADSAFE]: THREADSAFE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > Overview > Events Overview -------------------------------------------------------------------------------- # Events Overview SIMPL+ is an event driven language. There are eight functions, or event handlers, which deal with activating events in a given SIMPL+ program; CHANGE, CONNECT, DISCONNECT, EVENT, PUSH, RECEIVE, RELEASE and STATUS. | Event | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | CHANGE | The CHANGE event is called when a DIGITAL_INPUT transitions from low to high or high to low, or when an ANALOG_INPUT or STRING_INPUT changes. | | EVENT | Executes the defined anytime one of the inputs to the SIMPL+ symbol changes. It is similar to having a CHANGE statement listed for every input, and each change is set up to execute a common block of code. | | PUSH | PUSH is executed when a DIGITAL_INPUT transitions from low to high. | | RELEASE | RELEASE is executed when a DIGITAL_INPUT transitions from high to low. | | SOCKETCONNECT | The SOCKETCONNECT event is called when a socket connection is completed on a TCP_CLIENT or TCP_SERVER variable. | | SOCKETDISCONNECT | The SOCKETDISCONNECT event is called when a TCP_CLIENT or TCP_SERVER socket is disconnected. | | SOCKETRECEIVE | The SOCKETRECEIVE event is called when a TCP_CLIENT or TCP_SERVER socket receives data. | | SOCKETSTATUS | The SOCKETSTATUS event is called when the status of a TCP_CLIENT or TCP_SERVER socket changes. | | THREADSAFE | When using the THREADSAFE keyword before an event (such as PUSH, RELEASE, CHANGE) the event is prevented from retriggering, until the entire code block in the event has executed. Events prevented from triggering WILL be dropped. | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > PUSH -------------------------------------------------------------------------------- # PUSH Name: PUSH Syntax:     PUSH \ [, \ ...]     {        [Local Variable Definitions]        \     } Description: PUSH is executed when a DIGITAL_INPUT transitions from low to high. \ is a DIGITAL_INPUT type. On the rising edge of \, the statements between the opening { and closing } are executed. When using DIGITAL_INPUT arrays, only a change in the entire array can be detected, not an individual element. Refer to [GetLastModifiedArrayIndex] for a method of detecting a change to an individual element. When listing multiple variable names, the names can be put on the same line or broken up into several PUSH statements for readability. (see also [StackedEvents] AND [THREADSAFE]) Example:     DIGITAL_INPUT trigger;     STRING_OUTPUT output$;     PUSH trigger     {       output$ = "Hello, World!";     } In this example, when the DIGITAL_INPUT trigger transitions from low to high, the STRING_OUTPUT output$ will have the string "Hello, World!" put into it. Version: X Generation: SIMPL v1.20.01 and later SIMPL v1.50.06 and later, DIGITAL_INPUT arrays as \ 2-Series: SIMPL v2.01.05 and later [Same as X Generation SIMPL v1.50.06] and Local Variables allowed within PUSH Statements. [GetLastModifiedArrayIndex]: ../Array_Operations/GetLastModifiedArrayIndex.md [StackedEvents]: Stacked_Events.md [THREADSAFE]: THREADSAFE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > Release > RELEASE -------------------------------------------------------------------------------- # RELEASE Name: RELEASE Syntax:     RELEASE \ [, \ ...]     {       [Local Variable Definitions]       \     } Description: RELEASE is executed when a DIGITAL_INPUT transitions from high to low. \ is a DIGITAL_INPUT type. On the trailing edge of \, the statements between the opening { and closing } are executed. When using DIGITAL_INPUT arrays, only a change in the entire array can be detected, not an individual element. Refer to [GetLastModifiedArrayIndex] for a method of detecting a change to an individual element. When listing multiple variable names, the names can be put on the same line or broken up into several RELEASE statements for readability. (See also [StackedEvents] and [THREADSAFE]) Example:     DIGITAL_INPUT trigger;     STRING_OUTPUT output$;     RELEASE trigger     {       output$ = "Hello, World!";     } In this example, when the DIGITAL_INPUT trigger transitions from high to low, the STRING_OUTPUT output$ will have the string "Hello, World!" put into it. Version: X Generation: SIMPL v1.20.01 and later SIMPL v1.50.06 and later, DIGITAL_INPUT arrays as \ 2-Series: SIMPL v2.01.05 and later [Same as X Generation SIMPL v1.50.06] and Local Variables allowed within RELEASE statements. [GetLastModifiedArrayIndex]: ../Array_Operations/GetLastModifiedArrayIndex.md [StackedEvents]: Stacked_Events.md [THREADSAFE]: THREADSAFE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > Stacked Events -------------------------------------------------------------------------------- # Stacked Events Stacked Events Refers to multiple CHANGE, PUSH, or RELEASE functions followed by a single block of code (complex statement). NOTE:  Only CHANGE, PUSH, or RELEASE functions are used in stacked events. If necessary, refer to the descriptions of each function for details. A typical event statement may appear as:     PUSH var1, var2     {       // code     } SIMPL+ allows event stacking, which allows a block of code to be called from different CHANGE, PUSH, or RELEASE statements. An example is:     STRING_INPUT A$[100];     DIGITAL_INPUT IN1, IN2, IN3, IN4;     ANALOG_INPUT LEVEL;     ANALOG_INPUT PRESETS[5];     PUSH IN1     PUSH IN2     CHANGE IN3, LEVEL, A$, PRESETS     RELEASE IN3, IN4     {       // code     } This allows one piece of code to execute from many different types of event statements. NOTE: An input signal can be used in more than one event function.  The order of execution is as follows: \ The  order for a PUSH:\  PUSH statements in the order they appear in the source.\  CHANGE statements in the order they appear in the source EVENT statement. \ \ The  order for a RELEASE:\  RELEASE statements in the order they appear in the source.\  CHANGE statements in the order they appear in the source EVENT statement. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Events > THREADSAFE -------------------------------------------------------------------------------- # THREADSAFE Name: THREADSAFE Syntax:     THREADSAFE EVENT { }     THREADSAFE PUSH \ { }     THREADSAFE RELEASE \ { }     THREADSAFE CHANGE \ { }     THREADSAFE SOCKETCONNECT \ { }     THREADSAFE SOCKETDISCONNECT \ { }     THREADSAFE SOCKETRECEIVE \ { }     THREADSAFE SOCKETSTATUS \ { } Description: When using the THREADSAFE keyword before an event (such as PUSH, RELEASE, CHANGE) the event is prevented from retriggering, until the entire code block in the event has executed. Events prevented from triggering WILL be dropped. Please be aware, that the value of the digital (in case of PUSH and RELEASE) or Analog/Serial (in case of CHANGE) can still change while the THREADSAFE event is running. The THREADSAFE keyword will eliminate the need for adding a programmatic Semaphore to the body of the event. NOTE:  Events prevented from triggering WILL be dropped Example: DIGITAL_INPUT DigInp; THREADSAFE PUSH DigInp {       // code } NOTE:  The above example is equivalent to this: DIGITAL_INPUT DigInp; INTEGER semaphore; FUNCTION Main {    semaphore = false; } PUSH DigInp {    If( semaphore = false )    {       semaphore = true;       // code       semaphore = false;    } } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series:  v3.02.00 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Example Programs > Example 1 Hello, World! > Example 1: Hello, World! -------------------------------------------------------------------------------- # Example 1: Hello, World!     // A digital input from the SIMPL program DIGITAL_INPUT TRIG;     // Upon the digital signal TRIG going high or low, the Hello,     // World! message is printed.     CHANGE TRIG     {       PRINT("Hello, World!\n");     }     // Main is only called once when the system starts up or is reset.     FUNCTION MAIN()     {       PRINT("Main Starts!\n");     } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Example Programs > Example 2 8-Level switch on a Pesa switcher > Example 2: 8-Level switch on a Pesa switcher -------------------------------------------------------------------------------- # Example 2: 8-Level switch on a Pesa switcher     #SYMBOL_NAME "Pesa Switcher - 8 Levels"     #HINT "Creates Pesa CPU-Link H command for Switching"     /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*       DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS     \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/     // Digital trigger from the SIMPL program - this sends the command     // string out.     DIGITAL_INPUT TRIG;     // Analogs for the output and 8 levels of the switcher from the     // SIMPL program.     ANALOG_INPUT     OUTPUT,LEVEL1,LEVEL2,LEVEL3,LEVEL4,LEVEL5,LEVEL6,LEVEL7,LEVEL8;     // The output string that is to be sent from the SIMPL+ program to     // the SIMPL program to the switcher.     STRING_OUTPUT COMMAND$;     /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*       Global Variables       (Uncomment and declare global variables as needed)     \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/     INTEGER I, COUNT, CKSLOW, CKSHI;     STRING PESABUF[30];     /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*       Event Handlers       (Uncomment and declare additional event handlers as needed)     \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/     PUSH TRIG       {       // Format command which stores the switcher command in a       // temporary buffer. A Command looks like H{out}{l1}{l2}...{l8}       // {2 byte checksum}{CR}{LF} where {out} and {l1}..{l8} are 3       // digit ASCII bytes with leading 0s. An example is       // H001001002003004005006007008{2 bytes checksum}{CR}{LF}       // makestring(PESABUF,"H%03d%03d%03d%03d%03d%03d%03d%03d%03d",       // OUTPUT, LEVEL1, LEVEL2, LEVEL3, LEVEL4, LEVEL5, LEVEL6,       // LEVEL7, LEVEL8);         COUNT=0;  // Checksum count initialized to 0.         // Add each byte in the string to the running count.         for(i=1 to len(pesabuf))             COUNT = COUNT + BYTE(PESABUF, I);     // The checksum is computed by taking the COUNT and throwing         // away all but the lower byte. The upper nibble + '0' is the         // high order checksum byte, the lower nibble + '0' is the low         // order checksum byte.         // Compute the low byte of the checksum.         CKSLOW = (COUNT & 0x0F) + '0';         // Compute the high byte of the checksum.         CKSHI = ((COUNT & 0xF0) \>\> 4) + '0';         // Send the checksum command to the COMMAND$ that gets routed         // to the switcher via the SIMPL program.         makestring(COMMAND$, "%s%s%s", PESABUF, CHR(CKSLOW),         CHR(CKSHI));     } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Example Programs > Example 3 Computing The Number of Days In a Month (Using Functions) > Example 3: Computing the Number of Days in a Month (Using Functions) -------------------------------------------------------------------------------- # Example 3: Computing the Number of Days in a Month (Using Functions)     #SYMBOL_NAME "Compute Number of Days in a Month"     #ANALOG_INPUT MONTH;     #ANALOG_OUTPUT DAYS;     INTEGER_FUNCTION ComputeDaysInMonth(INTEGER Month)     {       // Note that this computation does NOT take into account leap       // year!       INTEGER Days;       SWITCH (Month)       {         CASE( 2): Days = 28; // February         CASE( 4): Days = 30; // April         CASE( 6): Days = 30; // June         CASE( 9): Days = 30; // September         CASE(11): Days = 30; // November         Default:  Days = 31;  // All others       }       Return(Days);     }     CHANGE MONTH     {       DAYS = ComputeDaysInMonth(MONTH);     } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Example Programs > Example 4 Computing The Number of Days In a Month (Using Function Libraries) > Example 4: Computing the Number of Days in a Month (Using Function Libraries) -------------------------------------------------------------------------------- # Example 4: Computing the Number of Days in a Month (Using Function Libraries) The following code would be saved as, in this example, "My Function Library.USL".     INTEGER_FUNCTION ComputeDaysInMonth(INTEGER CurrentMonth)     {       // Note that this computation does NOT take into account leap       // year!       INTEGER NumDays;      SWITCH(CurrentMonth)       {         CASE( 2): NumDays = 28; // February         CASE( 4): NumDays = 30; // April         CASE( 6): NumDays = 30; // June         CASE( 9): NumDays = 30; // September         CASE(11): NumDays = 30; // November         Default:  NumDays = 31;  // All others       }       Return(NumDays);     } The following code can be saved as any filename:     #SYMBOL_NAME "Compute Number of Days in a Month"     #USER_LIBRARY "My Function Library"     ANALOG_INPUT CURRENTMONTH;     ANALOG_OUTPUT NUMDAYS;     CHANGE CURRENTMONTH     {       NUMDAYS = ComputeDaysInMonth(CURRENTMONTH);     } -------------------------------------------------------------------------------- ## Language Constructs & Functions > Exception Handling > Exception Handling Error Codes > Exception Return Error Codes -------------------------------------------------------------------------------- # Exception Return Error Codes | | | |------------------------------|-------| | CODE | VALUE | | SPLUS_EXCEPTION_UNKNOWN | -4000 | | SPLUS_EXCEPTION_OUT_OF_RANGE | -4001 | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Exception Handling > GetExceptionCode -------------------------------------------------------------------------------- # GetExceptionCode Name: GetExceptionCode Syntax:     GetExceptionCode Description: Exceptions caught within TRY-CATCH blocks can also be evaluated using the GetExceptionCode function.   The code will either be [SPLUS_EXCEPTION_OUT_OF_RANGE] or [SPLUS_EXCEPTION_UNKNOWN][SPLUS_EXCEPTION_OUT_OF_RANGE]. Example: Function MyFunc( INTEGER index ) {    INTEGER intArr[10];    TRY    {       intArr[index] = 1;       Print( "array index set" );    }    CATCH    {       Switch( GetExceptionCode() )       {          case (SPLUS_EXCEPTION_OUT_OF_RANGE):          {          }          case (SPLUS_EXCEPTION_UNKNOWN):          {          }       }    } } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [SPLUS_EXCEPTION_OUT_OF_RANGE]: Exception_Handling_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Exception Handling > GetExceptionMessage -------------------------------------------------------------------------------- # GetExceptionMessage Name: GetExceptionMessage Syntax:     GetExceptionMessage Description: Exceptions caught within TRY-CATCH blocks can also be evaluated using the GetExceptionMessage function.  The message will contain a description of the error thrown. Example:  Function MyFunc( INTEGER index ) { INTEGER intArr[10]; TRY { intArr[index] = 1; Print( “array index set” ); } CATCH { Print( “Exception thrown: %s”, GetExceptionMessage() } } } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above -------------------------------------------------------------------------------- ## Language Constructs & Functions > Exception Handling > TRY-CATCH -------------------------------------------------------------------------------- # TRY-CATCH Name: TRY-CATCH Syntax:     TRY { \ } CATCH { statements } Description: TRY-CATCH blocks catch and handle exceptions generated by working code.  Exceptions can be caught and handled in the CATCH portion of the block.  The exception can also be evaluated using either the [GetExceptionMessage] or [GetExceptionCode] function. Example:  Function MyFunc( INTEGER index )  { INTEGER intArr[10]; TRY { intArr[index] = 1; Print( “array index set” ); } CATCH { Print( “array index out of bounds: %d”, index ); } } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [GetExceptionMessage]: GetExceptionMessage.md [GetExceptionCode]: GetExceptionCode.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Expressions & Statements -------------------------------------------------------------------------------- # Expressions & Statements An expression consists of operators and operands. i.e.     5 \* 6 or     (VAL1 + 5) / 30 or      (26 + BYTE(THESTRING$,1)) MOD Z = 25 Statements consist of function calls, expressions, assignments, or other instructions. There are two types of statements, Simple and Complex. A simple statement ends with a semicolon (;). Examples of simple statements are:     X = Z/10;                   // Simple assignment statement using                                 // operators.     PRINT("Hello, World!\n");   // Simple statement using a function                                 // call.     CHECKSUM = ATOI(Z$) + 5;    // Simple assignment statement using                                 // a function call and operators. A complex statement is a collection of simple statements that start with '{' and end with '}'. An example would be:     { // Start of a complex statement       X = Z/10;                 // Simple assignment statement                                 // using operators.       PRINT("Hello, World!\n"); // Simple statement using a                                 // function call.       CHECKSUM = ATOI(Z$) + 5;  // Simple assignment statement                                 // using a function call and                                 // operators.     } // End of a Complex statement -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > CheckForDisk -------------------------------------------------------------------------------- # CheckForDisk Name: CheckForDisk Syntax:     INTEGER CheckForDisk() Description: Tests whether or not a compact flash card is currently installed in the control system. Parameters: None. Return Value: Returns 1 if a compact flash card is currently installed in the control system. see also [WaitForNewDisk][]() Example: (see [File Functions Overview])     StartFileOperations(); // all file operations must first identify themselves with the operating system     IF ( CheckForDisk () = 1 )       PRINT ( "compact flash card found" );     EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [WaitForNewDisk]: WaitForNewDisk.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > CheckForNVRAMDisk -------------------------------------------------------------------------------- # CheckForNVRAMDisk Name: CheckForNVRAMDisk Syntax: INTEGER CheckForNVRAMDisk() Description: Tests whether or not an NVRam Disk is currently installed in the control system. Parameters: None. Return Value: Returns 1 if an NVRam Disk is currently installed in the control system. Example:     (refer to [File Functions Overview])     IF ( CheckForNVRAMDisk() = 1 )         PRINT ( "NVRAM Disk found" ); Version: X Generation:  Not Supported 2-Series:  SIMPL v2.04.11 and later [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > EndOfFileOperations > EndFileOperations -------------------------------------------------------------------------------- # EndFileOperations Name: EndFileOperations Syntax:     SIGNED_INTEGER EndFileOperations() Description: Signifies to the operating system that the current thread has completed its file operations. [StartFileOperations] is required prior to any operation accessing a file, including all functions in  [FileOpen]. EndFileOperations is required after finishing all file operations and prior to terminating the thread of execution (e.g., one of the PUSH commands). Parameters: None. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview])    IF ( StartFileOperations() \< 0 )       PRINT ( "Error in starting file ops\n" ); // various file operations     IF ( EndFileOperations() \< 0 )       PRINT ( "Error Occurred in ending file ops\n" ); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [StartFileOperations]: StartFileOperations.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileBOF -------------------------------------------------------------------------------- # FileBOF Name: FileBOF Syntax:     SIGNED_INTEGER FileBOF (INTEGER handle) Description: Tests whether or not the current file pointer is at the beginning of the file. Parameters: HANDLE specifies the file handle of the previously opened file (from [FileOpen]). Return Value: Returns 1 if beginning of file or 0 if not end of file. Otherwise, file [error code] is returned. Example: (see [File Functions Overview])     SIGNED_INTEGER  nFileHandle; StartFileOperations();     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \< 0)     {       PRINT("Error Opening File MyFile\n");       return;     }     IF ( FileBOF ( nFileHandle )  = 1 )       PRINT ( "Beginning of file reached\n" );     IF ( FileClose ( nFileHandle ) \<\> 0 )       PRINT ( "Error closing file" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileClose -------------------------------------------------------------------------------- # FileClose Name: FileClose Syntax:     SIGNED_INTEGER FileClose (INTEGER handle) Description: Closes a file opened previously by [FileOpen]. You MUST close a file that was opened, you won't be able to open it again, or eventually the control system may hang or reboot. A reboot clears all open files. Files must be opened and closed during a single thread of operation. Refer to [StartFileOperation]s. Parameters: HANDLE specifies the file handle of the previously opened file (from [FileOpen]). Return Value: Returns 0 if successful. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview])     SIGNED_INTEGER nFileHandle; StartFileOperations();     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \< 0)     {       PRINT("Error Opening File MyFile\n");       return;     }     IF (nFileHandle \>= 0)     {       IF ( FileClose ( nFileHandle ) \<\> 0 )         PRINT ( "Error closing file\n" );     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileOpen]: FileOpen.md [StartFileOperation]: StartFileOperations.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileDelete -------------------------------------------------------------------------------- # FileDelete Name: FileDelete Syntax:     SIGNED_INTEGER FileDelete (STRING filename) Description: Deletes the specified file from the file system. [FileOpen] and [FindFirst] should be used in conjunction with FileDelete when necessary. NOTE: Refer to the [File Functions Overview] topic statement on [Shared File Functions] for more information. Parameters: FILENAME specifies the name of the file to delete. Can contain wildcards (\*) if a full path is not given. Return Value: Returns 0 if successful. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview]) StartFileOperations();     IF ( FileDelete ( "\\CF0\\MyFile" ) \<\> 0 )       PRINT ( "Error deleting file\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileOpen]: FileOpen.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [error code]: File_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileDeleteShared -------------------------------------------------------------------------------- # FileDeleteShared Name: FileDeleteShared Syntax:     SIGNED_INTEGER FileDeleteShared (STRING filename) Description: Deletes the specified shared file from the file system. [FindFirstShared] and [FileOpenShared] should be used in conjunction with FileDeleteShared when necessary. NOTE: Refer to the [File Functions Overview] topic statement on [Shared File Functions] for more information. Parameters: FILENAME specifies the name of the file to delete. Can contain wildcards (\*) if a full path is not given. Return Value: Returns 0 if successful. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview]) StartFileOperations();     IF ( FileDeleteShared ( "\\CF0\\MyFile" ) \<\> 0 )       PRINT ( "Error deleting file\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [FindFirstShared]: FindFirstShared.md [FileOpenShared]: FileOpenShared.md [File Functions Overview]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [error code]: File_Function_Return_Error_Codes.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileEOF -------------------------------------------------------------------------------- # FileEOF Name: FileEOF Syntax:     SIGNED_INTEGER FileEOF (INTEGER handle) Description: Tests whether or not the current file pointer is at the end of the file. Parameters: HANDLE specifies the file handle of the previously opened file (from [FileOpen]). Return Value: Returns 1 if end of file or 0 if not end of file. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview])     SIGNED_INTEGER nFileHandle; StartFileOperations();     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \< 0)     {       PRINT("Error Opening File MyFile\n");       return;     }     IF ( FileEOF ( nFileHandle ) = 1 )       PRINT ( "End of file reached\n" );     IF ( FileClose ( nFileHandle ) \<\> 0 )       PRINT ( "Error closing file\n" );     EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileLength -------------------------------------------------------------------------------- # FileLength Name: FileLength Syntax:     LONG_INTEGER FileLength (INTEGER handle) Description: Returns the length of a file. Parameters: HANDLE specifies the file handle of the previously opened file (from [FileOpen]). Return Value: Number of bytes if successful. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview])  SIGNED_INTEGER nFileHandle; StartFileOperations();     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \< 0)     {       PRINT("Error Opening File MyFile\n");       return;     }  IF ( nFileHandle \> 0 )     PRINT ( "Length of file = %d\n",             FileLength ( nFileHandle ) );  IF ( FileClose ( nFileHandle ) \<\> 0 )     PRINT ( "Error closing file\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileOpen > FileOpen -------------------------------------------------------------------------------- # FileOpen Name: FileOpen Syntax:     SIGNED_INTEGER FileOpen (STRING filename, INTEGER flags) Description: *3-Series and 4-Series* Opens a file in the specified folder, prepending the Program ID Tag to the filename. For example, if you have a program called "HVAC" and want to open a file called "myFile.dat" in the directory, \NVRAM, the file “\NVRAM\HVAC\myFile.dat” will be opened. **Virtual Control** Opens a file in the specified folder. On Virtual Control, we will \*not\* prepend the Program ID Tag to the filename. For example, if you have a room called "HVAC" and want to open a file called "myFile.dat" in the directory, \NVRAM, the file “\NVRAM\\myFile.dat” will be opened for that specific room. Please see [File Functions Overview] for additional information.\ \ [FindFirst] and [FileDelete] should be used in conjunction with FileOpen when necessary. NOTE:  The function, [FileOpenShared] will not prepend the Program ID Tag to the filename. NOTE: Refer to the [File Functions Overview][1] topic statement on [Shared File Functions] for more information. Parameters: FILENAME specifies the full path name or relative path name (link) of the file to open/create. FLAGS – File Open Flags. Can be combined using the Bitwise OR operator (|) NOTE:  One of the following flags must be specified: _O_RDONLY, _O_WRONLY, or _O_RDWR. NOTE: When writing to the NVRAM disk, only one file can be open at one time.  Subsequent requests to write a file will block for a period of time (currently 5 seconds) until the initial write completes.  If the request times out, an error code of FILE_SHARE will be returned.  It is then up to the programmer to retry or signify an error condition. Open File Flags | | | |----|----| | KEYWORD | FUNCTION | | _O_APPEND | Writes done at the end of file.  Mutually exclusive with _O_TRUNC. | | _O_CREAT | Creates file.  If _O_APPEND is specified, the file will be created only if it doesn't already exist. | | _O_EXCL | Open succeeds only if file doesn't already exist. | | _O_TRUNC | Truncates file.  Mutually exclusive with _O_APPEND. | | _O_TEXT | Indicates the file is text. | | _O_BINARY | Indicates the file is binary (basically raw data). | | _O_RDONLY | Open file for reading only | | _O_RDWR | Open file for both reading and writing | | _O_WRONLY | Open file for writing only | Return Value: File handle if successful ( \>= 0). Otherwise, file [error code] is returned. NOTE:  [FileClose][]() must be called before the executing thread is terminated.  Failure to do so will result in the file being left open and locked by the control system.  Should this happen, the file will not be able to be opened again until the control system is rebooted. Examples:   (see [File Functions Overview][1]) 1\. Open a file for read only: SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );    IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); 2\. Open an existing file to log data to the end: SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpen ("\\CF0\\MyFile", _O_WRONLY | _O_APPEND) ; IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); 3\. If a file exists, truncate it and get rid of previous contents. If it doesn't exist, create it. SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpen ("\\CF0\\MyFile", _O_WRONLY | _O_CREAT | _O_TRUNC) ; IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");      } EndFileOperations(); 4\. Continue adding to the end of an existing log file, or create it if it does not already exist. SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpen ("\\CF0\\MyFile", _O_WRONLY | _O_APPEND | _O_CREAT); IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [File Functions Overview]: File_Functions_Overview.md [FindFirst]: File_First.md [FileDelete]: FileDelete.md [FileOpenShared]: FileOpenShared.md [1]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [error code]: File_Function_Return_Error_Codes.md [FileClose]: FileClose.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileOpenShared > FileOpenShared -------------------------------------------------------------------------------- # FileOpenShared Name: FileOpenShared Syntax:     SIGNED_INTEGER FileOpenShared (STRING filename, INTEGER flags) Description: *3-Series and 4-Series\* *Opens a file in the specified folder.  Unlike the function, [FileOpen], this function will not prepend the Program ID Tag with the filename.\* **Virtual Control** Opens a file in the specified folder. On Virtual Control, we will not prepend the Program ID Tag to the filename. For example, if you have a room called "HVAC" and want to open a file called "myFile.dat" in the directory, \NVRAM, the file “\NVRAM\\myFile.dat” will be opened for that specific room. Please see [File Functions Overview] for additional information. [FindFirstShared] and [FileDeleteShared] should be used in conjunction with FileOpenShared when necessary. NOTE: Refer to the [File Functions Overview][1] topic statement on [Shared File Functions] for more information. NOTE:  The function, [FileOpen][2], will prepend the Program ID Tag to the filename Parameters: FILENAME specifies the full path name or relative path name (link) of the file to open/create. FLAGS – File Open Flags. Can be combined using the Bitwise OR operator (|) NOTE:  One of the following flags must be specified: _O_RDONLY, _O_WRONLY, or _O_RDWR. NOTE: When writing to the NVRAM disk, only one file can be open at one time.  Subsequent requests to write a file will block for a period of time (currently 5 seconds) until the initial write completes.  If the request times out, an error code of FILE_SHARE will be returned.  It is then up to the programmer to retry or signify an error condition. Open File Flags | | | |----|----| | KEYWORD | FUNCTION | | _O_APPEND | Writes done at the end of file.  Mutually exclusive with _O_TRUNC. | | _O_CREAT | Creates file.  If _O_APPEND is specified, the file will be created only if it doesn't already exist. | | _O_EXCL | Open succeeds only if file doesn't already exist. | | _O_TRUNC | Truncates file.  Mutually exclusive with _O_APPEND. | | _O_TEXT | Indicates the file is text. | | _O_BINARY | Indicates the file is binary (basically raw data). | | _O_RDONLY | Open file for reading only | | _O_RDWR | Open file for both reading and writing | | _O_WRONLY | Open file for writing only | Return Value: File handle if successful ( \>= 0). Otherwise, file [error code] is returned. NOTE:  [FileClose][]() must be called before the executing thread is terminated.  Failure to do so will result in the file being left open and locked by the control system.  Should this happen, the file will not be able to be opened again until the control system is rebooted. Examples:   (see [File Functions Overview][1]) 1\. Open a file for read only: SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpenShared ( "\\CF0\\MyFile", _O_RDONLY );    IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); 2\. Open an existing file to log data to the end: SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpenShared ("\\CF0\\MyFile", _O_WRONLY | _O_APPEND) ; IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); 3\. If a file exists, truncate it and get rid of previous contents. If it doesn't exist, create it. SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpenShared ("\\CF0\\MyFile", _O_WRONLY | _O_CREAT | _O_TRUNC) ; IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");      } EndFileOperations(); 4\. Continue adding to the end of an existing log file, or create it if it does not already exist. SIGNED_INTEGER nFileHandle; StartFileOperations(); nFileHandle = FileOpenShared ("\\CF0\\MyFile", _O_WRONLY | _O_APPEND | _O_CREAT); IF (nFileHandle \< 0)    {    PRINT("Error Opening File MyFile\n");       } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md [FindFirstShared]: FindFirstShared.md [FileDeleteShared]: FileDeleteShared.md [1]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [2]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [FileClose]: FileClose.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileRead -------------------------------------------------------------------------------- # FileRead Name: FileRead Syntax:    SIGNED_INTEGER FileRead (INTEGER handle, STRING buffer, INTEGER count ) Description: Reads data from a file as a series of bytes into a buffer, starting at the current file position. Refer to the section entitled [Reading and Writing Data to a File]  for a discussion of when to use this function and when to use the related functions: [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. To avoid an error being generated by the console, use [FileEOF()] to test for end of file prior to reading. NOTE: Input and Output variables of any kind are not allowed in the file read functions. To read a single byte, use this function. Parameters: HANDLE specifies the file handle of the previously opened file (from [FileOpen]). BUFFER is the destination variable for bytes that are read. COUNT specifies the number of bytes to read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview])    SIGNED_INTEGER  nFileHandle;     STRING sBuf[4096]; StartFileOperations();     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)     {       WHILE (FileRead(nFileHandle, sBuf, 4096) \> 0)         PRINT ( "Read from file: %s\n", sBuf );       IF ( FileClose ( nFileHandle ) \<\> 0 )         PRINT ( "Error closing file\n" );     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileEOF()]: FileEOF.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileSeek -------------------------------------------------------------------------------- # FileSeek Name: FileSeek Syntax:     SIGNED_LONG_INTEGER FileSeek (INTEGER handle, SIGNED_LONG_INTEGER offset,                       INTEGER origin ) Description: Positions the current file pointer. Parameters: HANDLE specifies the file handle of previously opened file (from [FileOpen]). OFFSET specifies the number of bytes to move relative to the origin. ORIGIN is one of the file seek flags in the following table. File Seek Flags | | | |----------|---------------------------------------------| | KEYWORD | FUNCTION | | SEEK_SET | Start seeking from beginning of file | | SEEK_CUR | Start seeking from current position in file | | SEEK_END | Start seeking from end of file | Return Value: Number of bytes offset from the beginning of file. Otherwise, file [error code] is returned. Example:   (see [File Functions Overview])     SIGNED_INTEGER  nFileHandle; StartFileOperations();     nFileHandle = FileOpen("\\CF0\\MyFile", _O_RDONLY);     IF (nFileHandle \>= 0)     {       IF (FileSeek( nFileHandle, 0, SEEK_SET)) \< 0 )         PRINT ( "Error seeking file\n" );       IF ( FileClose ( nFileHandle ) \<\> 0 )         PRINT ( "Error closing file\n" );     } EndFileOperations(); Other Examples: 1\. Go to beginning of file\ FileSeek (nFileHandle,0,SEEK_SET) 2\. Go to end of file\ FileSeek (nFileHandle,0,SEEK_END) 3\. Get current file position\ CurrentBytePosition= FileSeek(nFileHandle,0,SEEK_CUR) Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FileWrite -------------------------------------------------------------------------------- # FileWrite Name: FileWrite Syntax:  SIGNED_INTEGER FileWrite (INTEGER handle, STRING buffer, INTEGER count ) Description: Writes data to a file as a series of bytes from a buffer, starting at the current file position. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions: [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray,] [WriteSignedIntegerArray], [WriteLongIntegerArr]ay, [WriteSignedLongIntegerArray,] [WriteStringArray.] NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. Parameters: HANDLE specifies the file handle of the previously opened file (from FileOpen). BUFFER is the variable containing the bytes to be written. COUNT specifies the number of bytes to write. Return Value: Number of bytes written to the file.  If the return value is negative, it is an error code. Example:   (see [File Functions Overview])   SIGNED_INTEGER  nFileHandle;     STRING sBuf[4096]; StartFileOperations();     sBuf = "Hello World!";     nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)     {       if( FileWrite(nFileHandle, sBuf, 4096) \> 0 )         PRINT ( "Written to file: %s\n", sBuf );       IF ( FileClose ( nFileHandle ) \<\> 0 )         PRINT ( "Error closing file\n" );     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray,]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArr]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray,]: WriteSignedLongIntegerArray.md [WriteStringArray.]: WriteStringArray.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > File First > FindFirst -------------------------------------------------------------------------------- # FindFirst Name: FindFirst Syntax:     SIGNED_INTEGER FindFirst(STRING filespec, FILE_INFO info) Description: This command searches a directory for file(s) matching the given file specification. Always followed with a [FindClose]. Requires [StartFileOperations()]. [FileOpen] and [FileDelete] should be used in conjunction with FindFirst when necessary. NOTE: Refer to the [File Functions Overview] topic statement on [Shared File Functions] for more information. Parameters: FILESPEC specifies the filename to look for. It can be a full path name or a [relative path name] with wildcards ( the ‘\*’ character). INFO – FILE_INFO structure containing the information about a found file: File Attribute Bit Flags (May be checked with bitwise & character) | | | |---------|---------------------------------| | KEYWORD | ATTRIBUTE | | ARDONLY | File is marked read only | | AHIDDEN | File is hidden | | ASYSTEM | File is marked as a system file | | AVOLUME | File is a volume label | | ADIRENT | File is a directory | | ARCHIVE | File is marked as archived | Return Value: Returns 0 if a file is found matching the specification and –1 if an error occurred. Example: (see [File Functions Overview])     FILE_INFO FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       IF ((FileInfo.iAttributes & ADIRENT)\<\>0)  PRINT ( "%s is a directory\n",FileInfo.Name); else  PRINT ("%s is a file\n",FileInfo.Name);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindClose]: FindClose.md [StartFileOperations()]: StartFileOperations.md [FileOpen]: FileOpen.md [FileDelete]: FileDelete.md [File Functions Overview]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [relative path name]: ../../General_Information/Relative_Path_Names_for_Files.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > File Function Return Error Codes -------------------------------------------------------------------------------- # File Function Return Error Codes | | | | |----|----|----| | KEYWORD | VALUE | FUNCTION | | FILE_BAD_USER | -3000 | Calling task is not a file user. Use StartFileOperations() first. | | FILE_NO_DISK | -3004 | Disk is removed. | | FILE_LONGPATH | -3017 | Path or directory name too long. | | FILE_INVNAME | -3018 | Path or filename includes invalid character. | | FILE_PEMFILE | -3019 | No file descriptors available (Too many files open). | | FILE_BADFILE | -3020 | Invalid file descriptor. | | FILE_ACCES | -3021 | Attempt to open a read-only file or special (directory). Also the error code you get when trying to make a directory on a volume that does not support it (i.e. NVRAM or internal flash). | | FILE_NOSPC | -3022 | No space to create file in this disk. | | FILE_SHARE | -3023 | The access conflicts from multiple tasks to a specific file. Can also occur when attempting to write multiple files to the NVRAM disk at the same time. | | FILE_NOFILE | -3024 | File not found. | | FILE_EXIST | -3025 | Exclusive access requested, but file already exists. | | FILE_NVALFP | -3026 | Seek to negative file pointer. | | FILE_MAXFILE_SIZE | -3027 | Over the maximum file size. | | FILE_NOEMPTY | -3028 | Directory is not empty. | | FILE_INVPARM | -3029 | Invalid Flag/Mode is specified. | | FILE_INVPARCMB | -3030 | Invalid Flag/Mode combination. | | FILE_NO_MEMORY | -3031 | Can't allocate internal buffer. | | FILE_NO_BLOCK | -3032 | No block buffer available. | | FILE_NO_FINODE | -3033 | No FINODE buffer available. | | FILE_NO_DROBJ | -3034 | No DROBJ buffer available. | | FILE_IO_ERROR | -3035 | Driver I/O function routine returned. | | FILE_INTERNAL | -3036 | Internal error. | | FILE_UNAUTH    | -4000 | Unauthorized access. | | FILE_TYPEUNSUPP    | -4001 | Type not supported. | | FILE_INVENC | -4002 | Invalid encoding found when reading a string. | | FILE_BINERR | -4003 | Cannot write binary data to file opened with TEXT flag. | | FILE_CORRUPT | -4004 | Header on the file is invalid - file cannot be opened. | | FILE_NEWER_VERSION | -4005 | The file version number is greater than what is supported. Compile Simpl+. | -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > File Functions Overview > File Functions Overview -------------------------------------------------------------------------------- # File Functions Overview File Functions perform file handle access from SIMPL+. 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 (function main say) and then access the file with the returned file handle in another (say an event handler). This is to prevent two events from writing to different parts of a file. This means that you should open, access and then close a file within the same thread.  For example, a program might be structured as follows: STRING sBuf[1000]; SIGNED_INTEGER nFileHandle; CHANGE input {         SIGNED_INTEGER nNumRead;         StartFileOperations();         nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );         if ( nFileHandle \>= 0 )         { nNumRead=FileRead( nFileHandle, sBuf, 500; Print ("Read Error\n"); FileClose( nFileHandle );         }         EndFileOperations(); } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Main() Uncomment and place one-time startup code here (This code will get called when the system starts up) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ Function Main() { SIGNED_INTEGER nNumWritten;         StartFileOperations();         nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );         if ( nFileHandle \>= 0 )         {                 sBuf = "Hello World!";                 nNumWritten=FileWrite( nFileHandle, sBuf, 500 );  if(nNumWritten\<0) Print ("WriteError");                 FileClose( nFileHandle );         }         EndFileOperations(); } Shared File Functions. There are now shared file functions in SIMPL+. The shared file functions are briefly described in the following paragraphs: [FileOpenShared] opens a file in the specified folder.  Unlike the function, [FileOpen], this function will not prepend the Program ID Tag with the filename.  FileOpen opens a file in the specified folder, prepending the Program ID Tag to the filename.  For example, if you have a program called "HVAC" and want to open a file called "myFile.dat" in the directory, \NVRAM, the file “\NVRAM\HVAC\myFile.dat” will be opened. [FindFirst] and [FileDelete] should be used in conjunction with FileOpen. [FindFirstShared] and [FileDeleteShared] should be used in conjunction with FileOpenShared. Virtual Control: By default, Virtual Control installs in/opt/crestron/virtualcontrol/and any rooms that are started have their own separate folder in /opt/crestron/virtualcontrol/RunningPrograms/ROOMID. Where ROOMID here is the unique ID that is used when the room gets created. For example, when/User/File.txtis opened on Virtual Control, /opt/crestron/virtualcontrol/RunningPrograms/ROOMID/User/File.txt is actually opened. On Virtual Control, every program runs in a single “room” and there is no sharing between rooms. So, for Virtual Control specific, FileOpen() and FileOpenShared() will both go to the exact same folder and won’t prepend Program ID Tag with the filename. This is different from 3-Series and 4-Series behavior and won’t prepend Program ID Tag with the filename. This is different from 3-Series and 4-Series behavior. [StartFileOperations]: StartFileOperations.md [EndFileOperations]: EndOfFileOperations.md [FileOpenShared]: FileOpenShared.md [FileOpen]: FileOpen.md [FindFirst]: File_First.md [FileDelete]: FileDelete.md [FindFirstShared]: FindFirstShared.md [FileDeleteShared]: FileDeleteShared.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > File INFO Structure > FILE_INFO Structure -------------------------------------------------------------------------------- # FILE_INFO Structure Use this structure to retrieve information about a file.        STRUCTURE FILE_INFO         {              STRING Name;            // relative name of the found file              INTEGER iAttributes;    // attributes for the file              INTEGER iTime;          // file time in packed form              INTEGER iDate;          // file date in packed form              LONG_INTEGER lSize;     // size of the file in bytes         }; File Attribute Bit Flags (These may be bitwise OR'ed together) | | | | |---------|---------------------------------|----------------------------| | KEYWORD | ATTRIBUTE | EQUIVALENT SIMPL+ FUNCTION | | ARDONLY | File is marked read only | IsReadOnly | | AHIDDEN | File is hidden | IsHidden | | ASYSTEM | File is marked as a system file | IsSystem | | AVOLUME | File is a volume label | IsVolume | | ADIRENT | File is a directory | IsDirectory | | ARCHIVE | File is marked as an archive | | NOTE: For an example on how and where to use the FILE_INFO structure, refer to the example code for [FindFirst]. Version: SIMPL+ Version 3.00.02 or higher (2-series only) [FindFirst]: File_First.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > File Time and Date Functions Overview -------------------------------------------------------------------------------- # File Time and Date Functions Overview These versions of the Time and Date functions in a given SIMPL+ program are used to retrieve information about the current date and time from the file info structure returned from [FINDFIRST]/[FINDNEXT]. Values can be retrieved as text strings i.e. "January" or integer values. Typically, integer values are used if computations need to be performed (i.e. when the date is the 25th, perform a specific action). [FINDFIRST]: File_First.md [FINDNEXT]: FindNext.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FindClose -------------------------------------------------------------------------------- # FindClose Name: FindClose Syntax:    SIGNED_INTEGER FindClose() Description: Signifies to the operating system that the find operation has ended. Always follows a [FindFirst] or [FindNext]. Parameters: None. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview])  [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       PRINT ( "%s\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: File_First.md [FindNext]: FindNext.md [File Functions Overview]: File_Functions_Overview.md [FILE_INFO]: File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FindFirstShared -------------------------------------------------------------------------------- # FindFirstShared Name: FindFirstShared Syntax:     SIGNED_INTEGER FindFirstShared(STRING filespec, FILE_INFO info) Description: This command searches a directory for file(s) matching the given file specification (first file shared). Always followed with a [FindClose]. Requires [StartFileOperations()]. [FileOpenShared] and [FileDeleteShared] should be used in conjunction with FindFirstShared when necessary. NOTE: Refer to the [File Functions Overview] topic statement on [Shared File Functions] for more information. Parameters: FILESPEC specifies the filename to look for. It can be a full path name or a [relative path name] with wildcards ( the ‘\*’ character). INFO – FILE_INFO structure containing the information about a found file: File Attribute Bit Flags (May be checked with bitwise & character) | | | |---------|---------------------------------| | KEYWORD | ATTRIBUTE | | ARDONLY | File is marked read only | | AHIDDEN | File is hidden | | ASYSTEM | File is marked as a system file | | AVOLUME | File is a volume label | | ADIRENT | File is a directory | | ARCHIVE | File is marked as archived | Return Value: Returns 0 if a file is found matching the specification and –1 if an error occurred. Example: (see [File Functions Overview])     FILE_INFO FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirstShared("\*.dat", FileInfo );     WHILE (Found = 0)     {       IF ((FileInfo.iAttributes & ADIRENT)\<\>0)  PRINT ( "%s is a directory\n",FileInfo.Name); else  PRINT ("%s is a file\n",FileInfo.Name);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [FindClose]: FindClose.md [StartFileOperations()]: StartFileOperations.md [FileOpenShared]: FileOpenShared.md [FileDeleteShared]: FileDeleteShared.md [File Functions Overview]: File_Functions_Overview.md [Shared File Functions]: javascript:void(0); [relative path name]: ../../General_Information/Relative_Path_Names_for_Files.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > FindNext -------------------------------------------------------------------------------- # FindNext Name: FindNext Syntax:     SIGNED_INTEGER FindNext(FILE_INFO info) Description: This command continues the current directory for file(s) matching the file specification in the [FindFirst] command. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Must be followed by a [FindClose]. Return Value: Returns 0 if a file is found matching the specification and –1 if an error occurred. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       PRINT ( "%s\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: File_First.md [FindClose]: FindClose.md [File Functions Overview]: File_Functions_Overview.md [FILE_INFO]: File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > GetCurrentDirectory -------------------------------------------------------------------------------- # GetCurrentDirectory Name: GetCurrentDirectory Syntax:     STRING GetCurrentDirectory() Description: Returns the complete path name of the current working directory. Refer to [Relative Path Names] for a discussion of setting the current directory. It ends with "\\. Parameters: None. Return Value: String containing the current directory.  If an error occurs, string length equals 0. Example:   (see [File Functions Overview])    PRINT( "The current directory =  %s\n", GetCurrentDirectory()); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Relative Path Names]: ../../General_Information/Relative_Path_Names_for_Files.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ISDIRECTORY > IsDirectory -------------------------------------------------------------------------------- # IsDirectory Name: IsDirectory Syntax:     INTEGER IsDirectory([FILE_INFO] info) Description: This routine returns whether the specified file is a directory, equivalent to checking info.;Attributes. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: Returns 1 if  file is a directory and 0 otherwise. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found;  StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       if (IsDirectory(FileInfo))           PRINT( "%s is a directory\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" );  EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [FILE_INFO]: File_INFO_Structure.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ISHIDDEN > IsHidden -------------------------------------------------------------------------------- # IsHidden Name: IsHidden Syntax:     INTEGER IsHidden(FILE_INFO info) Description: This routine returns whether the specified file is hidden. Equivalent to checking attributes in [FILE_INFO]. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: Returns 1 if file is hidden and 0 if otherwise. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found;  StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       if (IsHidden(FileInfo))           PRINT( "%s is hidden\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" );  EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FILE_INFO]: File_INFO_Structure.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ISREADONLY > IsReadOnly -------------------------------------------------------------------------------- # IsReadOnly Name: IsReadOnly Syntax:     INTEGER IsReadOnly(FILE_INFO info) Description: This routine returns whether the specified file is marked as read-only. Equivalent to checking attributes in [FILE_INFO]. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: Returns 1 if file is read-only and 0 if otherwise. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found;  StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       if (IsReadOnly(FileInfo))           PRINT( "%s is read-only\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" );  EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FILE_INFO]: File_INFO_Structure.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ISSYSTEM > IsSystem -------------------------------------------------------------------------------- # IsSystem Name: IsSystem Syntax:     INTEGER IsSystem(FILE_INFO info) Description: This routine returns whether the specified file is a system file. Equivalent to checking attributes in [FILE_INFO]. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: Returns 1 if file is a system file and 0 if otherwise. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found;  StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       if (IsSystem(FileInfo))           PRINT( "%s is a system file\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" );  EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FILE_INFO]: File_INFO_Structure.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ISVOLUME > IsVolume -------------------------------------------------------------------------------- # IsVolume Name: IsVolume Syntax:     INTEGER IsVolume(FILE_INFO info) Description: This routine returns whether the specified file is a volume label. Equivalent to checking attributes in [FILE_INFO]. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: Returns 1 if file is a volume label and 0 if otherwise. Example:   (see [File Functions Overview])     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found;  StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       if (IsVolume(FileInfo))           PRINT( "volume label = %s\n", FileInfo.Name );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" );  EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later [FILE_INFO]: File_INFO_Structure.md [FindFirst]: File_First.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > IsNull -------------------------------------------------------------------------------- # IsNull **Name:** IsNull **Syntax:**      INTEGER IsNull( \ ) **Description:** IsNull can be used to determine whether or not a class or class member variable is valid. **ReturnValue:** IsNull will return 1 if the class or class member variable has not been properly initialized, 0 otherwise. **Example:** CMutex myMutex; FUNCTIONInit() {      INTEGER retVal;      if ( \!IsNull(myMutex) )      {           myMutex.WaitForMutex();      }      else      { print(" myMutex is initialized!\r\n");      } } **Version:** X Generation: N/A 2-Series: N/A 3-Series:  SIMPL v4.02.02+ -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > MakeDirectory -------------------------------------------------------------------------------- # MakeDirectory Name: MakeDirectory Syntax:     SIGNED_INTEGER MakeDirectory(STRING DirName) Description: Creates a directory with the specified name. The path can be [relative] or absolute. NOTE: You cannot use MakeDirectory to create directories in the NVRAM or internal flash. You can only make directories in compact flash. Parameters: DIRNAME – string containing the name of the desired directory. Return Value: Returns 0 if successful. Returns 0 or a [File Function Error Code] if unsuccessful. Example:   (see [File Functions Overview])    IF( MakeDirectory("NewDirect") \< 0)        PRINT("Error occurred creating directory\n"); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [relative]: ../../General_Information/Relative_Path_Names_for_Files.md [File Function Error Code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > MakeDirectoryShared -------------------------------------------------------------------------------- # MakeDirectoryShared Name: MakeDirectoryShared Syntax:     SIGNED_INTEGER MakeDirectoryShared(STRING DirName) Description: Creates a shared directory with the specified name. The path can be [relative] or absolute. NOTE: You cannot use MakeDirectoryShared to create directories in the NVRAM or internal flash. You can only make directories in compact flash. Parameters: DIRNAME – string containing the name of the desired directory. Return Value: Returns 0 if successful. Returns 0 or a [File Function Error Code] if unsuccessful. Example:   (see [File Functions Overview])    IF( MakeDirectoryShared("NewDirect") \< 0)        PRINT("Error occurred creating directory\n"); Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [relative]: ../../General_Information/Relative_Path_Names_for_Files.md [File Function Error Code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadInteger -------------------------------------------------------------------------------- # ReadInteger Name: ReadInteger Syntax:     SIGNED_INTEGER ReadInteger ( INTEGER file_handle, INTEGER i ) Description: Reads an integer from a file starting at the current file position. Two bytes are read, most significant byte first. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead],  [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray][ReadIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). I is the integer whose value is read. Return Value: Number of bytes read from file.  If the return value is negative, it is an error code.\ If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; INTEGER i; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadInteger(nFileHandle, i);       if (iErrorCode \> 0)         PRINT ( "Read integer from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL v2.02.10 and later [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadIntegerArray -------------------------------------------------------------------------------- # ReadIntegerArray Name: ReadIntegerArray Syntax:   SIGNED_INTEGER ReadIntegerArray( INTEGER file_handle, INTEGER iArray[m][n] ) Description: Reads the array from a file starting at the current file position. Two bytes are read, most significant first containing the row dimension of the array, then two more bytes are read, containing the column dimension of the array. Then each integer is read as a two byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are read, because there is a row 0 and a column 0.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). IARRAY is the array whose values are read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. An error occurs if the array is not large enough to hold the data. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; INTEGER iArray[10]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadIntegerArray(nFileHandle, iArray);       if (iErrorCode \> 0)         PRINT ( "Read array from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadLongInteger -------------------------------------------------------------------------------- # ReadLongInteger Name: ReadLongInteger Syntax:   SIGNED_INTEGER ReadLongInteger ( INTEGER file_handle, LONG_INTEGER li ) Description: Reads a long integer from a file starting at the current file position. Four bytes are read, most significant byte first and least significant byte last.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger],  [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). LI is the long integer whose value is read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; LONG_INTEGER li; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadLongInteger(nFileHandle, li);       if (iErrorCode \> 0)         PRINT ( "Read long integer from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadLongIntegerArray -------------------------------------------------------------------------------- # ReadLongIntegerArray Name: ReadLongIntegerArray Syntax:     SIGNED_INTEGER ReadLongIntegerArray ( INTEGER file_handle, LONG_INTEGER ilArray[m][n] ) Description: Reads the array from a file starting at the current file position. Two bytes are read, most significant first containing the row dimension of the array, then two more bytes are read, containing the column dimension of the array. Then each long  integer is read as a four byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are read, because there is a row 0 and a column 0. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions.\   An error occurs if the array is not large enough to hold the data. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). ilArray is the array whose values are read. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; LONG_INTEGER ilArray[10]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadLongIntegerArray(nFileHandle, ilArray);       if (iErrorCode \> 0)         PRINT ( "Read array from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadSignedInteger -------------------------------------------------------------------------------- # ReadSignedInteger Name: ReadSignedInteger Syntax:    SIGNED_INTEGER ReadSignedInteger ( INTEGER file_handle, SIGNED_INTEGER si ) Description: Reads a signed integer from a file starting at the current file position. Two bytes are read, most significant first. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray][ReadSignedIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SI is the signed integer whose value is read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_INTEGER si; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadSignedInteger(nFileHandle, si);       if (iErrorCode \> 0)         PRINT ( "Read signed integer from file correctly\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedLongIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadSignedIntegerArray -------------------------------------------------------------------------------- # ReadSignedIntegerArray Name: ReadSignedIntegerArray Syntax:     SIGNED_INTEGER ReadSignedIntegerArray ( INTEGER file_handle, SIGNED_INTEGER isArray[m][n] ) Description: Reads the array from a file starting at the current file position. Two bytes are read, most significant first containing the row dimension of the array, then two more bytes are read, containing the column dimension of the array. Then each signed integer is read as a two byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are read, because there is a row 0 and a column 0. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). ISARRAY is the array whose values are read. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. An error occurs if the array is not large enough to hold the data. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_INTEGER isArray[10][5]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadSignedIntegerArray(nFileHandle, isArray);       if (iErrorCode \> 0)         PRINT ( "Read array from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadSignedLongInteger -------------------------------------------------------------------------------- # ReadSignedLongInteger Name: ReadSignedLongInteger Syntax:  SIGNED_INTEGER ReadSignedLongInteger ( INTEGER file_handle, SIGNED_LONG_INTEGER sli ) Description: Reads data from a file starting at the current file position. Each element of the structure is read, without any padding bytes, that might actually be there in memory. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SLI is the signed long integer whose value is read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_LONG_INTEGER sli; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadSignedLongInteger(nFileHandle, sli);       if (iErrorCode \> 0)         PRINT ( "Read from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadSignedLongIntegerArray -------------------------------------------------------------------------------- # ReadSignedLongIntegerArray Name: ReadSignedLongIntegerArray Syntax:     SIGNED_INTEGER ReadSignedLongIntegerArray ( INTEGER file_handle, SIGNED_LONG_INTEGER sliArray[m][n] ) Description: Reads the array from a file starting at the current file position. Two bytes are read, most significant first containing the row dimension of the array, then two more bytes are read, containing the column dimension of the array. Then each signed long  integer is read as a four byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are read, because there is a row 0 and a column 0.. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file read functions. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SLIARRAY is the array whose values are read. Return Value: Number of bytes read from file.  If the return value is negative, it is an [error code]. If no Return Value is specified within an Integer_Function, then a 0 will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_LONG_INTEGER sliArray[10][5]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadSignedLongIntegerArray(nFileHandle, sliArray);       if (iErrorCode \> 0)         PRINT ( "Read array from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadString -------------------------------------------------------------------------------- # ReadString Name: ReadString Syntax:     SIGNED_INTEGER ReadString ( INTEGER file_handle, STRING s ) Description: Reads a string from a file starting at the current file position. Internally, the string is stored as a 2-byte length, most significant byte first, then the actual string bytes.  In the case of a string variable, the total number of bytes written is calculated from the size of the string, not the string allocation size. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions: [FileRead], [ReadInteger], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). S is the string whose value is read. Return Value: Number of bytes read from file into the string.  If the return value is negative, it is an [error code]. An error occurs if the string is not large enough to hold the data. If no Return Value is specified within an String_Function, then an empty string will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; STRING s[100]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadString( nFileHandle, s);       if (iErrorCode \> 0)         PRINT ( "Read string from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > ReadStringArray -------------------------------------------------------------------------------- # ReadStringArray Name: ReadStringArray Syntax:     SIGNED_INTEGER ReadStringArray ( INTEGER file_handle, STRING s[] ) Description: Reads a string from a file starting at the current file position. Internally, the string is stored with the first 2 bytes indicating the total number of string written, then each string follows as a 2-byte length, most significant byte first, then the actual string bytes. In the case of a string variable, the total number of bytes is calculated from the size of the string, not the string allocation size. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions: [FileRead], [ReadInteger], [ReadString], [ReadStructure], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). S is the string whose value is read. Return Value: Number of bytes read from file into the string.  If the return value is negative, it is an [error code]. An error occurs if the array is not large enough to hold the data. If no Return Value is specified within an String_Function, then an empty string will be returned by default. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; STRING s[100][100]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_RDONLY );     IF (nFileHandle \>= 0)    { iErrorCode = ReadStringArray( nFileHandle, s);       if (iErrorCode \> 0)         PRINT ( "Read string from file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadStructure]: Read_Structure.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > Read Structure > ReadStructure -------------------------------------------------------------------------------- # ReadStructure Name: ReadStructure Syntax:    ReadStructure ( INTEGER nFileHandle, STRUCTURE struct [, INTEGER nTotalBytesRead] ) Description: Reads data from a file starting at the current file position. Each element of the structure is read, without any padding bytes, that might actually be there in memory. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileRead], [ReadInteger], [ReadString], [ReadSignedInteger], [ReadLongInteger], [ReadSignedLongInteger], [ReadIntegerArray], [ReadSignedIntegerArray], [ReadLongIntegerArray], [ReadSignedLongIntegerArray], [ReadStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables.\ There is no error if the structure does not match the data. Parameters: nFileHandle - File handle of the previously opened file (from [FileOpen]). struct - Structure variable that will receive data read from file nTotalBytesRead - optional argument.  INTEGER variable that will contain the total number of bytes read from the file into the structure. Return Value: NONE Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, nTotalBytesRead; STRUCTURE PhoneBookEntry {    STRING Name[50];    STRING Address[100];    STRING PhoneNumber[20]; }; PhoneBookEntry OneEntry; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile.txt", _O_RDONLY ); if (nFileHandle \>= 0) {    ReadStructure( nFileHandle, OneEntry, nTotalBytesRead );    if( nTotalBytesRead \< 0 )       PRINT ( "Error reading structure.  Error code = %d\n", nTotalBytesRead );    else       PRINT ( "Read structure from file correctly.  Total bytes read = %d\n", nTotalBytesRead ); } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileRead]: FileRead.md [ReadInteger]: ReadInteger.md [ReadString]: ReadString.md [ReadSignedInteger]: ReadSignedInteger.md [ReadLongInteger]: ReadLongInteger.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [ReadIntegerArray]: ReadIntegerArray.md [ReadSignedIntegerArray]: ReadSignedIntegerArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > Reading and Writing Data to a File -------------------------------------------------------------------------------- # Reading and Writing Data to a File Reading and writing data to a file that is moved from one kind of a system to another has special programming considerations because it will likely be written on one kind of system, e.g. a PC and read on another, e.g. a Crestron control system, or vice versa.  Most programmers are used to writing programs that are both written by a PC and read by a PC. The best way to write to a file that must be transferred between systems is to write pure ASCII text and use the [FileRead]/[FileWrite] routines. If you must write binary data as binary, e.g. structures, integers, strings, arrays, please read and consider the following. Different kinds of systems store their internal data structures with various padding bytes and lengths, that are not always apparent. For example, a structure declared like this: STRUCTURE { STRING s[5]; INTEGER I; } may contain a padding byte between the string and the integer, so the integer can begin on a word boundary. But this padding is  system and compiler dependent, as another system or compiler may handle this data perfectly well without a padding byte.  Also, some systems store integers with their most significant byte first ( the industry term is “big-endian”) or with their least significant bytes first (“little-endian”). Because compact flash is meant to be transferred among different systems, Crestron has given the programmer two different ways to store data. It can be stored with padding bytes by writing the integers, strings, structures, etc directly (see [WriteInteger], [WriteString], [WriteStructure], [WriteIntegerArray], etc) or it can be stored directly as a string of bytes where the programmer controls exactly what is written (see [FileWrite]). There are corresponding functions to read each of these. Data written by one method should be read with the corresponding function. If you must write binary files, Crestron recommends the first way, for system independence. Details are listed in each function. [FileRead]: FileRead.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteIntegerArray]: WriteIntegerArray.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > RemoveDirectoryShared -------------------------------------------------------------------------------- # RemoveDirectoryShared Name: RemoveDirectoryShared Syntax:     SIGNED_INTEGER RemoveDirectoryShared(STRING DirName) Description: Removes the shared directory with the specified name. The path name can be [relative] or absolute. Must be empty. Requires [StartFileOperations]. Parameters: DIRNAME – string containing the name of the desired directory. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview])    IF( RemoveDirectoryShared("\\CF0\\NewDirect") \< 0)        PRINT("Error occurred deleting directory\n"); Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above [relative]: ../../General_Information/Relative_Path_Names_for_Files.md [StartFileOperations]: StartFileOperations.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > Remove Directory > RemoveDirectory -------------------------------------------------------------------------------- # RemoveDirectory Name: RemoveDirectory Syntax:     SIGNED_INTEGER RemoveDirectory(STRING DirName) Description: Removes the directory with the specified name. The path name can be [relative] or absolute. Must be empty. Requires [StartFileOperations]. Parameters: DIRNAME – string containing the name of the desired directory. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview])    IF( RemoveDirectory("\\CF0\\NewDirect") \< 0)        PRINT("Error occurred deleting directory\n"); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [relative]: ../../General_Information/Relative_Path_Names_for_Files.md [StartFileOperations]: StartFileOperations.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > SetCurrentDirectory -------------------------------------------------------------------------------- # SetCurrentDirectory Name: SetCurrentDirectory Syntax:     SIGNED_INTEGER SetCurrentDirectory(STRING DirName) Description: Changes the working directory to the specified name. Refer to [Relative Path Names]. Parameters: DIRNAME – string containing the name of the desired directory. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview])    IF( SetCurrentDirectory("\\CF0\\NewDirect") \< 0)        PRINT("Error occurred creating directory\n");    PRINT("Directory is now: %s\n", GetCurrentDirectory()); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Relative Path Names]: ../../General_Information/Relative_Path_Names_for_Files.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > StartFileOperations -------------------------------------------------------------------------------- # StartFileOperations Name: StartFileOperations Syntax:     SIGNED_INTEGER StartFileOperations() Description: Signifies to the operating system that the current thread is starting its file operations. Required prior to any operation accessing a file, including all functions in [FileFunctions]. [EndFileOperations] is required after finishing all file operations and prior to terminating the thread of execution (e.g., one of the PUSH commands). Parameters: None. Return Value: Returns 0 if successful and –1 if an error occurred. Example:   (see [File Functions Overview][FileFunctions], specifically refer to the note about StartFileOperations)    IF ( StartFileOperations() \< 0 )       PRINT ( "Error in starting file ops\n" ); // various file operations     IF ( EndFileOperations() \< 0 )       PRINT ( "Error Occurred in ending file ops\n" ); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FileFunctions]: File_Functions_Overview.md [EndFileOperations]: EndOfFileOperations.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WaitForNewDisk -------------------------------------------------------------------------------- # WaitForNewDisk Name: WaitForNewDisk Syntax:     SIGNED_INTEGER WaitForNewDisk() Description: Waits for a compact flash card to be inserted into the control system. See also [CheckForDisk()]. Parameters: None. Return Value: Returns 0 when a new compact flash card is installed into the control system, \<0 if an error occurs. Example:   (see [File Functions Overview])     while(1)         {              if ( WaitForNewDisk() \< 0 )                         break;              // perform operations on the new disk. Read a file, etc.         } Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [CheckForDisk()]: CheckForDisk.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteInteger -------------------------------------------------------------------------------- # WriteInteger Name: WriteInteger Syntax:     SIGNED_INTEGER WriteInteger ( INTEGER file_handle, INTEGER i ) Description: Writes an integer to a file starting at the current file position. Two bytes are written, most significant byte first. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadInteger] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). I is the integer whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; INTEGER i; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteInteger(nFileHandle, i);       if (iErrorCode \> 0)         PRINT ( "Written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadInteger]: ReadInteger.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteIntegerArray -------------------------------------------------------------------------------- # WriteIntegerArray Name: WriteIntegerArray Syntax:    SIGNED_INTEGER WriteIntegerArray( INTEGER file_handle, INTEGER iArray[m][n] ) Description: Writes the array to a file starting at the current file position. Two bytes are written, most significant first containing the row dimension of the array, then two more bytes are written, containing the column dimension of the array. Then each integer is written as a two byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are written, because there is a row 0 and a column 0.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadIntegerArray] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). IARRAY is the array whose values are written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; INTEGER iArray[10]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteIntegerArray(nFileHandle, iArray);       if (iErrorCode \> 0)         PRINT ( "Array written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadIntegerArray]: ReadIntegerArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteLongInteger -------------------------------------------------------------------------------- # WriteLongInteger Name: WriteLongInteger Syntax:     SIGNED_INTEGER WriteLongInteger ( INTEGER file_handle, LONG_INTEGER li ) Description: Writes a long integer to a file starting at the current file position. Four bytes are written, most significant byte first.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray,] [WriteLongIntegerArray], [WriteSignedLongIntegerArray,] [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables.\ Use [ReadLongInteger] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). LI is the long integer whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; LONG_INTEGER li; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteLongInteger(nFileHandle, li);       if (iErrorCode \> 0)         PRINT ( "Written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray,]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray,]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadLongInteger]: ReadLongInteger.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteLongIntegerArray -------------------------------------------------------------------------------- # WriteLongIntegerArray Name: WriteLongIntegerArray Syntax:     SIGNED_INTEGER WriteLongIntegerArray ( INTEGER file_handle, LONG_INTEGER ilArray[m][n] ) Description: Writes the array to a file starting at the current file position. Two bytes are written, most significant first containing the row dimension of the array, then two more bytes are written, containing the column dimension of the array. Then each long  integer is written as a four byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are written, because there is a row 0 and a column 0. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Use [ReadLongIntegerArray] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). ilArray is the array whose values are Write. Return Value: Number of bytes written to the file.  If the return value is negative, it is an error code. Example:   (see [File Functions Overview]) INTEGER  nFileHandle, iErrorCode; LONG_INTEGER ilArray[10]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteLongIntegerArray(nFileHandle, ilArray);       if (iErrorCode \> 0)         PRINT ( “Array written to file correctly.\n");       else         PRINT ( “Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadLongIntegerArray]: ReadLongIntegerArray.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteSignedInteger -------------------------------------------------------------------------------- # WriteSignedInteger Name: WriteSignedInteger Syntax:    SIGNED_INTEGER WriteSignedInteger ( INTEGER file_handle, SIGNED_INTEGER si ) Description: Writes a signed integer to a file starting at the current file position. Two bytes are written, most significant first. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadSignedInteger] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SI is the signed integer whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_INTEGER si; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteSignedInteger(nFileHandle, si);       if (iErrorCode \> 0)         PRINT ( "Written to file correctly\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadSignedInteger]: ReadSignedInteger.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteSignedIntegerArray -------------------------------------------------------------------------------- # WriteSignedIntegerArray Name: WriteSignedIntegerArray Syntax:    SIGNED_INTEGER WriteSignedIntegerArray ( INTEGER file_handle, SIGNED_INTEGER isArray[m][n] ) Description: Writes the array to a file starting at the current file position. Two bytes are written, most significant first containing the row dimension of the array, then two more bytes are Write, containing the column dimension of the array. Then each signed integer is written as a two byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are written, because there is a row 0 and a column 0. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadSigned IntegerArray] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). ISARRAY is the array whose values are Write. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_INTEGER isArray[10][5]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteSignedIntegerArray(nFileHandle, isArray);       if (iErrorCode \> 0)         PRINT ( "Array written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: ReadSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadSigned IntegerArray]: ReadSignedIntegerArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteSignedLongInteger -------------------------------------------------------------------------------- # WriteSignedLongInteger Name: WriteSignedLongInteger Syntax:   SIGNED_INTEGER WriteSignedLongInteger ( INTEGER file_handle, SIGNED_LONG_INTEGER sli ) Description: Writes data to a file starting at the current file position. Each element of the structure is written, without any padding bytes, that might actually be there in memory. Refer to the section titled\ “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger,] [WriteLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Use [ReadSignedLongInteger] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SLI is the signed long integer whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an error code. Example:   (see [File Functions Overview]) INTEGER  nFileHandle, iErrorCode; SIGNED_LONG_INTEGER sli; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteSignedLongInteger(nFileHandle, sli);       if (iErrorCode \> 0)         PRINT ( "Written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger,]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadSignedLongInteger]: ReadSignedLongInteger.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteSignedLongIntegerArray -------------------------------------------------------------------------------- # WriteSignedLongIntegerArray Name: WriteSignedLongIntegerArray Syntax:  SIGNED_INTEGER WriteSignedLongIntegerArray ( INTEGER file_handle, SIGNED_LONG_INTEGER sliArray[m][n] ) Description: Writes the array to a file starting at the current file position. Two bytes are written, most significant first containing the row dimension of the array, then two more bytes are written, containing the column dimension of the array. Then each signed long  integer is written as a four byte quantity, most significant byte first. The integers are stored in row-major order, e.g. all the elements of row 0 first, then the elements of  row 1, etc. Note that there is one more row and one more column than the dimensions that are written, because there is a row 0 and a column 0.. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadSignedLongIntegerArray] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). SLIARRAY is the array whose values are written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; SIGNED_LONG_INTEGER sliArray[10][5]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteSignedLongIntegerArray(nFileHandle, sliArray);       if (iErrorCode \> 0)         PRINT ( "Array written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadSignedLongIntegerArray]: ReadSignedLongIntegerArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteString -------------------------------------------------------------------------------- # WriteString Name: WriteString Syntax:     SIGNED_INTEGER WriteString ( INTEGER file_handle, STRING s ) Description: Writes a string to a file starting at the current file position. Internally, the string is stored as a 2-byte length, most significant byte first, then the actual string bytes.  In the case of a string variable, the total number of bytes written is calculated from the size of the string, not the string allocation size.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions: [FileWrite], [WriteInteger], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadString] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). S is the string whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; STRING s[100]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteString( nFileHandle, s);       if (iErrorCode \> 0)         PRINT ( "String written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [WriteStringArray]: WriteStringArray.md [ReadString]: ReadString.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteStringArray -------------------------------------------------------------------------------- # WriteStringArray Name: WriteStringArray Syntax:     SIGNED_INTEGER WriteStringArray ( INTEGER file_handle, STRING s[] ) Description: Writes a string array to a file starting at the current file position. Internally, the string is stored with the first 2 bytes indicating the total number of strings written, then each string follows as a 2-byte length, most significant byte first, then the actual string bytes.  In the case of a string variable, the total number of bytes is calculated from the size of the string, not the string allocation size.  Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions: [FileWrite], [WriteInteger], [WriteString], [WriteStructure], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray,] [WriteLongIntegerArray,] [WriteSignedLongIntegerArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadStringArray] to read this. Parameters: FILE_HANDLE specifies the file handle of the previously opened file (from [FileOpen]). S is the string whose value is written. Return Value: Number of bytes written to the file.  If the return value is negative, it is an [error code]. Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, iErrorCode; STRING s[100][100]; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile", _O_WRONLY );     IF (nFileHandle \>= 0)    { iErrorCode = WriteStringArray( nFileHandle, s);       if (iErrorCode \> 0)         PRINT ( "String written to file correctly.\n");       else         PRINT ( "Error code %d\n", iErrorCode);     } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.03.18 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteStructure]: WriteStructure.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongInteger.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray,]: WriteSignedIntegerArray.md [WriteLongIntegerArray,]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongIntegerArray.md [ReadStringArray]: ReadStringArray.md [FileOpen]: FileOpen.md [error code]: File_Function_Return_Error_Codes.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > File Functions > WriteStructure -------------------------------------------------------------------------------- # WriteStructure Name: WriteStructure Syntax:      WriteStructure ( INTEGER nFileHandle, STRUCTURE struct [, INTEGER nTotalBytesWritten] ) Description: Writes data to a file starting at the current file position. Each element of the structure is written, without any padding bytes, that might actually be there in memory. Refer to the section entitled “[Reading and Writing Data to a File]” for a discussion of when to use this function and when to use the related functions:  [FileWrite], [WriteInteger], [WriteString], [WriteSignedInteger], [WriteLongInteger], [WriteSignedLongInteger], [WriteIntegerArray], [WriteSignedIntegerArray], [WriteLongIntegerArray], [WriteSignedLongIntegerArray], [WriteStringArray]. NOTE: Input and Output variables of any kind are not allowed in the file reading and writing functions, just internal variables. NOTE: Use [ReadStructure] to read this.  Parameters: nFileHandle - File handle of the previously opened file (from [FileOpen]). struct - Structure variable whose data will be written to the file nTotalBytesWritten - optional argument.  INTEGER variable that will contain the total number of bytes written to the file from the structure. Return Value: NONE Example:   (see [File Functions Overview]) SIGNED_INTEGER  nFileHandle, nTotalBytesWritten; STRUCTURE PhoneBookEntry {    STRING Name[50];   STRING Address[100];    STRING PhoneNumber[20]; }; PhoneBookEntry OneEntry; StartFileOperations(); nFileHandle = FileOpen ( "\\CF0\\MyFile.txt", _O_WRONLY ); if (nFileHandle \>= 0) {    WriteStructure( nFileHandle, OneEntry, nTotalBytesWritten );    if( nTotalBytesWritten \< 0 )       PRINT ( "Error writing structure.  Error code = %d\n", nTotalBytesWritten );    else       PRINT ( "Structure written to file correctly.  Total bytes written = %d\n", nTotalBytesWritten ); } EndFileOperations(); Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [Reading and Writing Data to a File]: Reading_and_Writing_Data_to_a_File.md [FileWrite]: FileWrite.md [WriteInteger]: WriteInteger.md [WriteString]: WriteString.md [WriteSignedInteger]: WriteSignedInteger.md [WriteLongInteger]: WriteLongInteger.md [WriteSignedLongInteger]: WriteSignedLongIntegerArray.md [WriteIntegerArray]: WriteIntegerArray.md [WriteSignedIntegerArray]: WriteSignedIntegerArray.md [WriteLongIntegerArray]: WriteLongIntegerArray.md [WriteSignedLongIntegerArray]: WriteSignedLongInteger.md [WriteStringArray]: WriteStringArray.md [ReadStructure]: Read_Structure.md [FileOpen]: FileOpen.md [File Functions Overview]: File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Functions Overview -------------------------------------------------------------------------------- # Functions Overview There are a number of different function types in SIMPL+. This topic is provided as a jumping off point in your exploration of the various types of functions that can be implemented in SIMPL+. [Bit & Byte Functions] [Data Conversion Functions] [Language Constructs and Functions] [Mathematical Functions] [Random Number Functions] [String Formatting and Printing Functions] [String Parsing and Manipulation Functions] [Time and Date Functions] [User-Defined Functions] [Bit & Byte Functions]: Bit_&_Byte_Functions/Overview.md [Data Conversion Functions]: Data_Conversion_Functions/Overview.md [Language Constructs and Functions]: Overview.md [Mathematical Functions]: Mathematical_Functions/Overview.md [Random Number Functions]: Random_Number_Functions/Overview.md [String Formatting and Printing Functions]: String_Formatting_&_Printing_Functions/Overview.md [String Parsing and Manipulation Functions]: String_Parsing_&_Manipulation_Functions/Overview.md [Time and Date Functions]: Time_&_Date_Functions/Overview.md [User-Defined Functions]: User_Defined_Functions/User_Defined_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > Overview > Interfacing to the CEN-OEM via a SIMPL+ Program Overview -------------------------------------------------------------------------------- # Interfacing to the CEN-OEM via a SIMPL+ Program Overview When using an X-Generation system to communicate over Ethernet to a CEN-OEM, the CEN-OEM definition is used from the SIMPL Configuration Manager. This symbol has analog inputs, analog outputs, digital inputs, digital outputs, serial inputs, and serial outputs. When a list of variables such as DIGITAL_INPUTs is declared, they normally start at Digital Input 1 on the symbol and progress linearly up. For some applications, it may be desirable to change the join numbers (leave gaps on the symbol) for a better visual look. NOTE: These directives apply only to the CEN-OEM device. [#ANALOG_INPUT_JOIN] [#ANALOG_OUTPUT_JOIN][][\ #DIGITAL_INPUT_JOIN] [#DIGITAL_OUTPUT_JOIN] [#STRING_INPUT_JOIN] [#STRING_OUTPUT_JOIN] [#ANALOG_INPUT_JOIN]: _ANALOG_INPUT_JOIN.md [#ANALOG_OUTPUT_JOIN]: _ANALOG_OUTPUT_JOIN.md [\ #DIGITAL_INPUT_JOIN]: _DIGITAL_INPUT_JOIN.md [#DIGITAL_OUTPUT_JOIN]: _DIGITAL_OUTPUT_JOIN.md [#STRING_INPUT_JOIN]: _STRING_INPUT_JOIN.md [#STRING_OUTPUT_JOIN]: _STRING_OUTPUT_JOIN.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > ANALOG INPUT JOIN > #ANALOG_INPUT_JOIN -------------------------------------------------------------------------------- # #ANALOG_INPUT_JOIN Name: #ANALOG_INPUT_JOIN Syntax:     #ANALOG_INPUT_JOIN\ Description: Changes the join number starting with the next ANALOG_INPUT definition to the join number specified by \. Example:     ANALOG_INPUT SIG1, SIG2, SIG3, SIG4; In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, and SIG4 references Join #4.     ANALOG_INPUT SIG1, SIG2;     #ANALOG_INPUT_JOIN 20     ANALOG_INPUT SIG3, SIG4; Here, SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, and SIG4 references Join #21. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > ANALOG OUTPUT JOIN > #ANALOG_OUTPUT_JOIN -------------------------------------------------------------------------------- # #ANALOG_OUTPUT_JOIN Name: #ANALOG_OUTPUT_JOIN Syntax:     #ANALOG_OUTPUT_JOIN\ Description: Changes the join number starting with the next ANALOG_OUTPUT definition to the join number specified by \. Example:     ANALOG_OUTPUT SIG1, SIG2, SIG3, SIG4; In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, and SIG4 references Join #4.     ANALOG_OUTPUT SIG1, SIG2;     #ANALOG_OUTPUT_JOIN 20     ANALOG_OUTPUT SIG3, SIG4; SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, and SIG4 references Join #21. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > DIGITAL INPUT JOIN > #DIGITAL_INPUT_JOIN -------------------------------------------------------------------------------- # #DIGITAL_INPUT_JOIN Name: #DIGITAL_INPUT_JOIN Syntax:     #DIGITAL_INPUT_JOIN\ Description: Changes the join number starting with the next DIGITAL_INPUT definition to the join number specified by \. Example:     DIGITAL_INPUT SIG1, SIG2, SIG3, SIG4; In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, and SIG4 references Join #4.     DIGITAL_INPUT SIG1, SIG2;     #DIGITAL_INPUT_JOIN 20     DIGITAL_INPUT SIG3, SIG4; SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, and SIG4 references Join #21. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > DIGITAL OUTPUT JOIN > #DIGITAL_OUTPUT_JOIN -------------------------------------------------------------------------------- # #DIGITAL_OUTPUT_JOIN Name: #DIGITAL_OUTPUT_JOIN Syntax:     #DIGITAL_OUTPUT_JOIN\ Description: Changes the join number starting with the next DIGITAL_OUTPUT definition to the join number specified by \. Example:     DIGITAL_OUTPUT SIG1, SIG2, SIG3, SIG4; In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, and SIG4 references Join #4.     DIGITAL_OUTPUT SIG1, SIG2;     #DIGITAL_OUTPUT_JOIN 20     DIGITAL_OUTPUT SIG3, SIG4; SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, and SIG4 references Join #21. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > STRING INPUT JOIN > #STRING_INPUT_JOIN -------------------------------------------------------------------------------- # #STRING_INPUT_JOIN Name: #STRING_INPUT_JOIN Syntax:     #STRING_INPUT_JOIN\ Description: Changes the join number starting with the next STRING_INPUT or BUFFER_INPUT definition to the join number specified by \. Example:     STRING_INPUT SIG1[20], SIG2[20], SIG3[20], SIG4[20];     BUFFER_INPUT B1$[20] In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, SIG4 references Join #4, and B1$ references Join#5.     STRING_INPUT SIG1[20], SIG2[20];     #STRING_INPUT_JOIN 20     STRING_INPUT SIG3[20], SIG4[20];     BUFFER_INPUT B1$[20] SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, SIG4 references Join #21, and B1$ references Join#22. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Interfacing to the CEN-OEM via a SIMPL Plus Program > STRING OUTPUT JOIN > #STRING_OUTPUT_JOIN -------------------------------------------------------------------------------- # #STRING_OUTPUT_JOIN Name: #STRING_OUTPUT_JOIN Syntax:     #STRING_OUTPUT_JOIN\ Description: Changes the join number starting with the next STRING_OUTPUT definition to the join number specified by \. Example:     STRING_OUTPUT SIG1, SIG2, SIG3, SIG4; In this example, SIG1 references Join #1, SIG2 references Join #2, SIG3 references Join #3, and SIG4 references Join #4.     STRING_OUTPUT SIG1, SIG2;     #STRING_OUTPUT_JOIN 20     STRING_OUTPUT SIG3, SIG4; SIG1 and SIG2 still reference Join #1 and Join #2, but SIG3 has been changed to reference Join #20, and SIG4 references Join #21. Version: CEN-OEM ONLY:  SIMPL v1.50.06 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Looping Constructs > DO - UNTIL -------------------------------------------------------------------------------- # DO - UNTIL Name: DO - UNTIL Syntax:     DO     [{]       \     [}] UNTIL (\); Description: This loop performs a set of \ at least one time and will terminate when \ evaluates to true. If only one statement is present in the body of the loop, then the { and } characters are not required, but may be used. If more than one statement is present in the loop body, then the { and } characters are mandatory. Note that \ is evaluated each time through the loop. Example:     INTEGER X;     X=0;     DO     {       X = X + 1;       PRINT("X = %d\n", X);     }     UNTIL (X = 25); In this example, the loop will execute 25 times. The PRINT function will show the value of X after it is incremented to the computer port of the control system. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Looping Constructs > FOR -------------------------------------------------------------------------------- # FOR Name: FOR Syntax:     FOR (\ = \ TO \         [STEP \])     [{]       \     [}] Description: This loop executes the \ while \ iterates from the value of \ to the value of \. The variable is incremented by \ at the end of the loop, if STEP is specified, else it is incremented by 1. The \ can be negative which will result in the loop counting down. If only one statement is present in the body of the loop, then the { and } characters are not required, but may be used. If more than one statement is present in the loop body, then the { and } characters are mandatory. Note that \ and \ are evaluated once before the loop starts and are not re-evaluated during the execution of the loop. If it is defined, \ is evaluated each pass through the loop, so \ may be modified during execution of the loop. In the 2-Series control systems, the \ cannot change its sign during the execution of the loop. That is, if it is initially a positive number, then it is assumed if it will always count up. If it is negative, it will always count down. NOTE:  If \ is set to a value greater than the \ within the body of the FOR loop, the FOR loop will exit when it reaches the end. At the end of the loop, the loop index has the value of \ + 1 (unless the loop index was modified in the body of the loop). The comparisons are based on signed numbers, the maximum loop size for a step of one would be from 1 to 32767. If larger indices are needed, for example, from 1 to 60000 a DO-UNTIL or WHILE loop could be used. Example:     STRING_INPUT IN$[100];     INTEGER X;     FOR (X = 1 TO LEN(IN$))     {       PRINT("Character %d of String %s is %s\n", X, IN$,             MID(IN$, X, 1));     } In this example, the loop will iterate through each character of a string and print out the string and its position in the original string. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Looping Constructs > Overview > Looping Constructs Overview -------------------------------------------------------------------------------- # Looping Constructs Overview Loops are used to perform a section of code zero or more times in a row in a given SIMPL+ program. The body of the loop can consist of statements, expressions, function calls, or other loops. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Looping Constructs > WHILE -------------------------------------------------------------------------------- # WHILE Name: WHILE Syntax:     WHILE(\)     [{]       \     [}] Description: This loop performs a set of \ as long as \ does not evaluate to zero. If only one statement is present in the body of the loop, then the { and } characters are not required, but may be used. If more than one statement is present in the loop body, then the { and } characters are mandatory. Note that depending on \, the body of the loop may never be executed. Note that \ is evaluated at the beginning of the loop. Example:     INTEGER X;     X=0;     WHILE(X \< 25)     {       X = X + 1;       PRINT("X = %d\n", X);     } In this example, the loop will execute 25 times. The PRINT function will show the value of X after it is incremented to the computer port of the control system. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > ABS > Abs -------------------------------------------------------------------------------- # Abs Name: Abs Syntax: INTEGER Abs(INTEGER SOURCE); INTEGER Abs(SIGNED_INTEGER SOURCE); Description: Takes the absolute value of SOURCE. If SOURCE is negative, a positive value is returned. If SOURCE is already positive, the same value is returned. Parameters: Takes the absolute value of an INTEGER. Return Value: An INTEGER corresponding to the absolute value of SOURCE. Example:     DIGITAL_INPUT TRIG;     INTEGER I, K;     I=-5;     CHANGE TRIG     {       K=ABS(I);       PRINT("Original Value = %d, Absolute Value = %d\n", I, K);     } The output would be:     Original Value = -5, Absolute Value = 5 Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > MAX > Max -------------------------------------------------------------------------------- # Max Name: Max Syntax:     INTEGER Max(INTEGER VAL1, INTEGER VAL2) Description: Determine the maximum of two values based on an unsigned comparison. Parameters: VAL1 and VAL2 are both INTEGER values on which the test is performed. Return Value: The maximum of Val1, Val2 after an unsigned comparison is performed. Refer to "Signed vs. Unsigned Arithmetic" on page 5 for a further explanation of how the values are compared. Example:     INTEGER X, Y;     FUNCTION MAIN()     {       X = MAX(65535, 0);       Y = MAX(25, 26);     } X would be 65535, and Y would be 26. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > MIN > Min -------------------------------------------------------------------------------- # Min Name: Min Syntax:     INTEGER Min(INTEGER VAL1, INTEGER VAL2) Description: Determine the minimum of two values based on an unsigned comparison. Parameters: VAL1 and VAL2 are both INTEGER values on which the test is performed. Return Value: The minimum of Val1, Val2 after an unsigned comparison is performed. Refer to "Signed vs. Unsigned Arithmetic" for a further explanation of how the values are compared. Example:     INTEGER X, Y;     FUNCTION MAIN()     {       X = MIN(65535, 0);       Y = MIN(25, 26);     } X would be 0, and Y would be 25. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > MULDIV > MulDiv -------------------------------------------------------------------------------- # MulDiv Name: MulDiv Syntax:     INTEGER MulDiv(INTEGER VAL1, INTEGER VAL2, INTEGER VAL3) Description: Computes the result (VAL1 \* VAL2)/VAL3. Parameters: VAL1, VAL2, and VAL3 are INTEGER values. Return Value: A 16-bit integer is returned based on the above equation. The arithmetic operations are performed using unsigned arithmetic. Note that 32-bit math is used internally, so that if VAL1\*VAL2 is greater than a 16-bit number, accuracy is maintained. If the final result is greater than 16-bits, the lower 16-bits are returned. Example:     INTEGER X, Y;     FUNCTION MAIN()     {       X = 1970;       Y = 40;       PRINT("The result of (%d \* %d)/25 = %d\n", X, Y,       MULDIV(X, Y, 25);     } The PRINT statement would show the result as being 3152. In this case, X\*Y is greater than a 16-bit number, but accuracy is maintained due to the use of 32-bit arithmetic internally. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > Overview > Mathematical Functions Overview -------------------------------------------------------------------------------- # Mathematical Functions Overview These functions perform general mathematical operations in a given SIMPL+ program by operating on one or more numerical arguments and returning an INTEGER as a result. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > SMAX -------------------------------------------------------------------------------- # SMAX Name: SMax Syntax:     INTEGER SMax(INTEGER VAL1, INTEGER VAL2) Description: Determine the maximum of two values based on a signed comparison. Parameters: VAL1 and VAL2 are both INTEGER values on which the test is performed. Return Value: The maximum of Val1, Val2 after a signed comparison is performed. Refer to "Signed vs. Unsigned Arithmetic" for a further explanation of how the values are compared. Example:     INTEGER X, Y;     FUNCTION MAIN()     {       X = SMAX(65535, 0);       Y = SMAX(25, 26);     } X would be 0 (65535 interpreted as -1), and Y would be 26. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Mathematical Functions > SMIN > SMin -------------------------------------------------------------------------------- # SMin Name: SMin Syntax:     INTEGER SMin(INTEGER VAL1, INTEGER VAL2) Description: Determine the minimum of two values based on a signed comparison. Parameters: VAL1 and VAL2 are both INTEGER values on which the test is performed. Return Value: The minimum of Val1, Val2 after a signed comparison is performed. Refer to "Signed vs. Unsigned Arithmetic" on page 5 for a further explanation of how the values are compared. Example:     INTEGER X, Y;     FUNCTION MAIN()     {       X = SMIN(65535, 0);       Y = SMIN(25, 26);     } X would be 65535 (interpreted as -1), and Y would be 25. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Overview > Language Constructs & Functions Overview -------------------------------------------------------------------------------- # Language Constructs & Functions Overview Functions take one or more comma separated parameters and return a result. The following template shows how each language construct and function is explained. Name: The name used to refer to the construct or function. Syntax: The SIMPL+ specific language requirements for this particular construct or function. This section demonstrates exactly how to enter the statement in a SIMPL+ program. For completeness, the general syntax for SIMPL+ functions is shown below:     \ FunctionName(\ [,     \ ...]); The Types are described as STRING, INTEGER, LONG_INTEGER, SIGNED_INTEGER, and SIGNED_LONG_INTEGER. If a STRING is specified as a return type, a STRING or STRING_OUTPUT variable may be used. If an INTEGER or LONG_INTEGER  is specified as a return type, an INTEGER, LONG_INTEGER, ANALOG_OUTPUT or DIGITAL_OUTPUT may be used. If a STRING is specified as a parameter, a STRING, STRING_INPUT, BUFFER_INPUT or literal string (i.e. "Hello") may be used. If an INTEGER,  LONG_INTEGER, SIGNED_INTEGER or SIGNED_LONG_INTEGER is specified as a parameter, an INTEGER, LONG_INTEGER, ANALOG_INPUT, ANALOG_OUTPUT, DIGITAL_INPUT or DIGITAL_OUTPUT may be used. A literal integer (i.e. 100) may also be used. Note that for DIGITAL_OUTPUT values, a value of 0 is equivalent to digital low, and any other value is a digital high. Description: General overview of what this function does. Parameters (applies to functions only): Specifics on each of the parameters listed. Return Value (applies to functions only): What values are placed in the return variable. Error conditions are also described here. Error conditions are results that occur if one or more of the input values does not have values that are legal for that function. Example: A code example of how this function is typically used. Version: The version of SIMPL+ in which the construct or function was made available and any revision notes about differences between various versions of SIMPL+. All constructs and functions are available in all subsequent versions except where noted. Control System: The control system platform for which the function is valid. Unless specified, the construct or function is valid for both X-Generation (eg., CEN-TVAV, CNMSX-AV/PRO, CNRACKX/-DP) and 2-Series control systems. SIMPL+ is not available in the control systems preceding the X generation - CNMS, CNRACK/-D/-DP, CNLCOMP/-232, and ST-CP -------------------------------------------------------------------------------- ## Language Constructs & Functions > Program Structure -------------------------------------------------------------------------------- # Program Structure When a new SIMPL+ program is created, a template is provided that lists the order in which constructs and statements should be defined. Sections can be uncommented and expanded out to implement the desired code. A SIMPL+ program layout would consist of, in order:                1. [Compiler Directives]                2. Input/Output definitions From/To a SIMPL Program                3. Global declarations for the module, including STRING, [INTEGER], [Arrays], [Structures], etc.                4. [FUNCTION] declarations                5. PUSH/RELEASE/CHANGE statements                6. FUNCTION MAIN NOTE:  All of these are not mandatory and may be left out as needed. NOTE:  In SIMPL+ Version 3.00, local variables are allowed. Forward references are not allowed in a SIMPL+ program. This means you cannot CALL a function before it has been defined. This is the reason FUNCTION declarations are placed before other code. If function A calls function B, then function B should be located first in the source file. FUNCTION MAIN is a special case function. It is not required, but any code present between the { and } is executed at startup. This is typically used for initialization purposes. For example:     FUNCTION MAIN()     {       MyVar=0;       For(I=1 to 10)          B[I] = I;     } Sometimes FUNCTION MAIN() contains an endless loop with a DELAY statement that executes periodically while the program runs. [Compiler Directives]: Compiler_Directives/Overview.md [INTEGER]: Declarations/INTEGER.md [Arrays]: Array_Operations/Arrays.md [Structures]: Declarations/STRUCTURES.md [FUNCTION]: Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > CompareRampsByAttribute() > CompareRampsByAttribute -------------------------------------------------------------------------------- # CompareRampsByAttribute Name: CompareRampsByAttribute Syntax:     SIGNED_INTEGER CompareRampsByAttribute (ANALOG_OUTPUT | ANALOG_INPUT signal, RAMP_INFO RampData); Description: This function compares the ramping process on the given signal to the ramp described by RampData. Specifically, it checks to make sure that the rampTransitionTime,  rampBaseValue and rampTargetValue are the same. Parameters: ANALOG_OUTPUT | ANALOG_INPUT signal RAMP_INFO RampData – the specific analog input or output to test against the described values of RampData in the RAMP_INFO structure. Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 3: There is no ramp process on the specified signal. 1: The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are the same. 0: The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are different. Example:   In this example, the SIMPL+ module will monitor the input signal.  If the input signal has a ramping process, it will copy it to the output.  It then stores the ramping information for future comparison; each time the input ramp changes, it will trigger this module, but the module will end up stopping once it realizes that it has already processed the ramping process that is on the input.  If there is no ramping process, it will simply copy the input value to the output value. ANALOG_INPUT InputLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO InputRampInfo, OutputRampInfo; Change InputLevel {   if(IsRamping(InputLevel))   {      if(CompareRampsByAttribute(InputLevel, InputRampInfo)=0)      {         GetRampInfo(InputLevel, InputRampInfo);         CreateRamp(OutputLevel, InputRampInfo);      }   }   else   {      OutputLevel = InputLevel;      InitializeRampInfo(InputRampInfo);   } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > CompareRampsByID() > CompareRampsByID -------------------------------------------------------------------------------- # CompareRampsByID Name: CompareRampsByID Syntax:     SIGNED_INTEGER CompareRampsByID (ANALOG_OUTPUT | ANALOG_INPUT signal, LONG_INTEGER ramp_identifier ); Description: This function compares the ID field of the ramp on the given signal to the [rampIdentifier] member of the RAMP_INFO structure as specified by the RampData variable. Parameters: ANALOG_OUTPUT | ANALOG_INPUT signal RAMP_INFO RampData – the specific analog input or output to compare with the RampData in the RAMP_INFO structure. Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 0: The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are different. 1: The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are the same. 3: There is no ramp process on the specified signal. Example:   This is a more efficient version of the code presented in CompareRampsByAttribute, as all It needs to do is check one long_integer.   ANALOG_INPUT InputLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO InputRampInfo, OutputRampInfo; LONG_INTEGER InputRampID; Change InputLevel {   if(IsRamping(InputLevel))   {      GetRampInfo(InputLevel, InputRampInfo);      If(InputRampInfo.rampIdentifier \<\> InputRampID)      {         CreateRamp(OutputLevel, InputRampInfo);      }   }   else   {      OutputLevel = InputLevel;      InitializeRampInfo(InputRampInfo);   } } function main() {    // By initializing our test-against ID to zero, we will guarantee that the first    // time a ramp is found in the change statement, the ramps will not be thought to    // be the same.    InputRampID = 0; } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [rampIdentifier]: Ramping_Functions.md [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > CreateRamp() > CreateRamp -------------------------------------------------------------------------------- # CreateRamp Name: CreateRamp Syntax:     SIGNED_INTEGER CreateRamp (ANALOG_OUTPUT signal, RAMP_INFO RampData); Description: Creates a ramping process on the specific ANALOG_OUTPUT. If the output already has a running ramping process on it this function will modify that process regardless of its origin. (e.g., rampTransitionTime could be increased or rampTargetValue could be reduced). The following members must be filled in by the user: rampLowerBound rampUpperBound rampBaseValue rampTargetValue rampTransitionTime rampIsAbsolute rampIsRunnable NOTE: See [Ramping Functions Defaults] for the default values of these members. Parameters: ANALOG_OUTPUT signal – the specific output on which to create the ramping process. It is legal to use an ANALOG_OUTPUT or an element of an ANALOG_OUTPUT array. RAMP_INFO RampData – a declared variable of RAMP_INFO used to hold information about the created ramping process. NOTE:  This function will change the following user-defined values in the RAMP_INFO structure: \ \ rampIsAbsolute: will be changed to 1 (Absolute) if the user specified that it would be Relative (\<\>1).\ \ rampTransitionTime: will be changed to the Absolute Transition Time reported by ANALOG_OUTPUT signal if the user originally specified rampTransitionTime as Relative (\<\>1).\ \ rampBaseValue: will be set to the value reported by ANALOG_OUT signal if rampBaseValue has been set to 100000. NOTE:  This function will fill in the following non-user specifiable values in the RAMP_INFO structure: \ \ rampBaseTime: will be automatically set to the system time at which the ramp was created.\ \ rampIdentifier: will be automatically set to distinguish the current ramp from any other existing ramps.\   Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 0: Ramping process created or modified successfully. Example:   In this example, an analog output array element is given a ramping process that will ramp from signal's current value to 10% (6553) in 10 seconds (1000). DIGITAL_INPUT GoToPresetLevel; ANALOG_OUTPUT LightLevel[20]; PUSH GoToPresetLevel {    RAMP_INFO LightInfo;    SIGNED_INTEGER status;    // 10% of 65535 is 6553.    LightInfo.rampTargetValue=6553;    // Always takes "rampTransitionTime" to go to the Target Value.      LightInfo.isAbsolute=1;    // Transition time of 10 seconds (1000 hundredths of a second)    LightInfo.rampTransitionTime=1000;    If(IsSignalDefined(LightLevel[1])    {           status = CreateRamp(LightLevel[1], LightInfo);      if(status \<\> 0)         GenerateUserWarning("Could not create Ramping Process, status = %d", status);    } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Functions Defaults]: javascript:void(0); [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > GetRampInfo() -------------------------------------------------------------------------------- # GetRampInfo() Name: GetRampInfo() Syntax:     SIGNED_INTEGER GetRampInfo (ANALOG_OUTPUT | ANALOG_INPUT signal, RAMP_INFO RampData) Description: This function populates the fields of the given RAMP_INFO structure with the information from the ramping process on the given output signal. Parameters: ANALOG_OUTPUT | ANALOG_INPUT signal RAMP_INFO RampData Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 0: The info on the ramping process on a given output was obtained successfully and placed into the RAMP_INFO structure. 3: There is no ramp process on the specified signal. Example:   ANALOG_INPUT InputLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO InputRampInfo, OutputRampInfo; Change InputLevel {   if(IsRamping(InputLevel))   {      if(CompareRampsByAttribute(InputLevel, InputRampInfo)=0)      {         GetRampInfo(InputLevel, InputRampInfo);         CreateRamp(OutputLevel, InputRampInfo);      }   }   else   {      OutputLevel = InputLevel;      InitializeRampInfo(InputRampInfo);   } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > InitializeRampInfo > InitializeRampInfo() -------------------------------------------------------------------------------- # InitializeRampInfo() Name: InitializeRampInfo() Syntax:     InitializeRampInfo(RAMP_INFO val) Description: Initializes the given RAMP_INFO structure to it's default state.  The value can be either an arrayed or non-arrayed structure.  The default states are the same as when the RAMP_INFO structure is declared. Refer to [Ramping Function Defaults]. This is useful for returning the structure back to a safe state after performing comparisons.  (see CompareRampsByAttribute(), CompareRampsByID()). Parameters: RAMP_INFO val: – the variable "val" of the type RAMP_INFO is initialized. Return Value: None Example:   ANALOG_INPUT InputLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO InputRampInfo, OutputRampInfo; Change InputLevel {   if(IsRamping(InputLevel))   {      if(CompareRampsByAttribute(InputLevel, InputRampInfo)=0)      {         GetRampInfo(InputLevel, InputRampInfo);         CreateRamp(OutputLevel, InputRampInfo);      }   }   else   {      OutputLevel = InputLevel;      InitializeRampInfo(InputRampInfo);   } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Function Defaults]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > InitializeRampInfoArray() -------------------------------------------------------------------------------- # InitializeRampInfoArray() Name: InitializeRampInfoArray() Syntax:     InitializeRampInfoArray(RAMP_INFO array[]) Description: Initializes each structure the given RAMP_INFO array to it's default state. The default states are the same as when the RAMP_INFO structure is declared: rampUpperBound:  65535 rampLowerBound:  0 rampBaseValue:  100000 rampTargetValue:  65535 rampBaseTime:  0 rampTransitionTime:  0 rampIsSigned:  0 rampIsAbsolute:  0 This is useful for returning the structure back to a safe state after performing comparisons.  (see CompareRampsByAttribute(), CompareRampsByID()). Parameters: RAMP_INFO array[ ] – a RAMP_INFO array is initialized. Return Value: None Example:   ANALOG_INPUT InputLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO InputRampInfo, OutputRampInfo; Change InputLevel {   if(IsRamping(InputLevel))   {      if(CompareRampsByAttribute(InputLevel, InputRampInfo)=0)      {         GetRampInfo(InputLevel, InputRampInfo);         CreateRamp(OutputLevel, InputRampInfo);      }   }   else   {      OutputLevel = InputLevel;      InitializeRampInfo(InputRampInfo);   } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > IsRamping() > IsRamping -------------------------------------------------------------------------------- # IsRamping Name: IsRamping Syntax:     SIGNED_INTEGER IsRamping (ANALOG_OUTPUT | ANALOG_INPUT signal); Description: This function determines if there is a ramping process present on the specified  ANALOG_OUTPUT signal. Parameters: ANALOG_OUTPUT | ANALOG_INPUT signal – the specific analog input or output to test for the presence of a ramping process. Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 1: There is a ramping process present on the specified signal. 3: There is no ramping process present on the specified signal. Example:   In this example, the SIMPL+ module will start a ramping transition on the analog output "LightingLevel" using the default RAMP_INFO structure values, only if there is no ramping process currently on it (i.e. an "Analog Ramp" symbol or other ramp-generating symbol currently has a ramping operation in progress on that analog output signal in SIMPL). DIGITAL_INPUT StartFade; ANALOG_INPUT LightingLevel; ANALOG_OUTPUT OutputLevel; RAMP_INFO LightInfo; Push StartFade {    if(IsRamping(LightingLevel) != 1)    { CreateRamp(OutputLevel, LightInfo);    } } Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > RAMP INFO Structure > RAMP_INFO Structure -------------------------------------------------------------------------------- # RAMP_INFO Structure These are the default values for the RAMP_INFO structure. | | | |--------------------|---------| | MEMBER | DEFAULT | | rampLowerBound | 0 | | rampUpperBound | 65535 | | rampBaseValue | 100000 | | rampTargetValue | 65535 | | rampTransitionTime | 500 | | rampIsAbsolute | 0 | | rampIsRunnable | 1 | | rampIdentifier | 0 | | rampBaseTime | 0 | -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > Ramping Function Return Error Codes -------------------------------------------------------------------------------- # Ramping Function Return Error Codes | | | | |----|----|----| | KEYWORD | VALUE | FUNCTION | | RAMP_ILLEGAL_BASE_VALUE | -22 | rampBaseValue is not within the bounds of rampUpperBound to rampLowerBound | | RAMP_ILLEGAL_TARGET_VALUE | -21 | rampTargetValue is not within the bounds of rampUpperBound to rampLowerBound | | RAMP_BOUNDS | -20 | Illegal bounds have been specified. Bounds must be -32768 to 32767 or 0 to 65535. An error message is placed in the error log. | | RAMP_INVALID | -15 | Invalid Ramp (Internal, Contact Crestron) | | RAMP_NO_CREATE | -14 | Could Not Create Ramp (Internal, Contact Crestron) | | RAMP_BAD_POINTER | -13 | Illegal internal Ramp Pointer (Internal, Contact Crestron) | | RAMP_ILLEGAL_ISABSOLUTE | -12 | Illegal value specified for rampIsAbsolute, must be 0 or 1. | | RAMP_NO_SIGNAL | -8 | No signal at given index.1 | | RAMP_SUCCESS | 0 | Ramping process created/modified successfully | | RAMP_DIFFERENT_RAMP2 | 0 | The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are the different. | | RAMP_RAMP_PRESENT | 1 | Ramp present on the given signal | | RAMP_SAME_RAMP2 | 1 | The ramping process on the specified signal and the data specified in the given RAMP_INFO structure are the same. | | RAMP_NO_RAMP | 2 | No Ramp on the signal to stop | | RAMP_NO_RAMP_PRESENT | 3 | No Ramp on the given signal | 1. This would typically happen if an element of an ANALOG_OUTPUT array is used that is not defined on the SIMPL symbol.  For example, ANALOG_OUTPUT levels[20]; is in the SIMPL+ program, and the symbol is only expanded to 5, but an attempt is made to create a ramping process on levels[15]. 2. Applies to CompareRampByAttribute and CompareRampsByID. only. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > Ramping Functions > Ramping Functions -------------------------------------------------------------------------------- # Ramping Functions Ramping functions make it possible to manage processes that smoothly transition an ANALOG_OUTPUT from one value to another over a specified period of time. In the past, it was necessary to use methods such as loops to issue multiple values or an oscillator to trigger a DIGITAL_INPUT to increment an ANALOG_OUTPUT in order to get the same effect. Functions are available for creation, destruction, detection and comparison. The Ramping functions use a pre-defined structure called RAMP_INFO.         STRUCTURE RAMP_INFO         {              SIGNED_LONG_INTEGER    // rampLowerBound;              SIGNED_LONG_INTEGER    // rampUpperBound;              SIGNED_LONG_INTEGER    // rampBaseValue;              SIGNED_LONG_INTEGER    // rampTargetValue;              INTEGER                // rampIsAbsolute;              LONG_INTEGER           // rampTransitionTime;              INTEGER                // rampIsRunnable;              LONG_INTEGER           // rampIdentifier;              LONG_INTEGER           // rampBaseTime;              INTEGER                // rampIsSigned;              INTEGER                // rampIsExpired;                     }; NOTE: Your choice of values for rampLowerBound, rampUpperBound, rampBaseValue and rampTargetValue must be consistent within a given RAMP_INFO function (shown later in this topic). Choose either the -32768 to 32767 range or the 0 to 65535 range. The members of RAMP_INFO are described as follows: | MEMBER | DESCRIPTION | NOTES | | ------------------ | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | rampLowerBound | The lowest possible value of the ramp. | Legal values are -32768 to 32767 or 0 to 65535. Default is 0. | | rampUpperBound | The highest possible value of the ramp. | Legal values are -32768 to 32767 or 0 to 65535. Default is 65535. | | rampBaseValue | The starting value of the ramp. | Legal values are -32768 to 32767 or 0 to 65535. Default is 1000001. The ramp will start from the current value of the signal on the ANALOG_OUT in SIMPL. The predefined constant; SIGNAL_DEFAULT_VALUE can also be used. | | rampTargetValue | The ending value of the ramp. | Legal values are -32768 to 32767 or 0 to 65535. Default is 65535. | | rampTransitionTime | The length of time (in units of 0.01sec.) for the ramping function to go from rampBaseValue to rampTargetValue. | The rampTransitionTime is dependent on the value of the rampIsAbsolute member. Default is 5002. | | rampIsAbsolute | Indicates whether or not the rampTransitionTime is relative (indicated by <>1) or absolute (indicated by 1). | If rampTransitionTime is relative, the rampTransitionTime will be the result of the following formula: If rampTransitionTime is absolute, the time to get from rampBaseValue to rampTargetValue is exactly as specified. Default is 0 (FALSE). Legal values are 0 and 1. | | rampIsRunnable | Specifies if the ramp actually creates values to put into a signal or if the ramp is a place holder. | If a SIMPL+ module is creating a ramp, like the Analog Ramp symbol does, then IsRunnable is 1. If the SIMPL+ module is looking at a ramp on an ANALOG_INPUT and then placing one on an ANALOG_OUTPUT, it should set IsRunnable=0, and the module itself should be responsible for setting the correct discrete value on the analog output. Default is 1 (TRUE). | | rampIdentifier | Used to distinguish one ramp from another where two ramps are in use. | Since two ramps can be created at the same time and have the same start/end values and rampTransitionTime, this member is used to distinguish one ramp from another. The system assigns the rampIdentifier. It is not user-specifiable. | | rampBaseTime | The system time at which the ramping process was created. | This member is not user-specifiable. | | rampIsSigned | | | | rampIsExpired | | | 1. The rampBaseValue default of 100000 is not a legal value for an analog signal (legal values are -32768 to 32767 or 0 to 65535). The default of 100000 means that when the ramp is launched it's value--the 100000--is replaced by the existing rampBaseValue from the ANALOG_OUTPUT signal parameter called by the [CreateRamp] function. 2. In SIMPL+ time is rendered in hundredths of a second. Therefore, 5 seconds is represented as 500. The functions available to the RAMP_INFO structure are: [CreateRamp] [StopRamp] [IsRamping] [GetRampInfo] [CompareRampsByAttribute] [CompareRampsByID] [InitializeRampInfo] [InitializeRampInfoArray] Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [CreateRamp]: CreateRamp().md [StopRamp]: StopRamp().md [IsRamping]: IsRamping().md [GetRampInfo]: GetRampInfo().md [CompareRampsByAttribute]: CompareRampsByAttribute().md [CompareRampsByID]: CompareRampsByID().md [InitializeRampInfo]: InitializeRampInfo.md [InitializeRampInfoArray]: InitializeRampInfoArray().md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Ramping Functions > StopRamp() > StopRamp -------------------------------------------------------------------------------- # StopRamp Name: StopRamp Syntax:     SIGNED_INTEGER StopRamp (ANALOG_OUTPUT signal); Description: This function unconditionally terminates, or stops, the ramping process on a given ANALOG_OUTPUT signal. Parameters: ANALOG_OUTPUT signal – the specific output of the ramping process you want to stop. It is legal to use an ANALOG_OUTPUT or an element of an ANALOG_OUTPUT array. Return Value: If the return value is negative, it is an error code. (see [Ramping Functions Error Codes]) The returned values for this function are as follows: 2: There is no Ramp Control Block (RCB) to stop on the specified signal. 0: RCB stopped successfully. Example:   In this example, when TerminateFade is driven high, the SIMPL+ module will stop the fade in progress on the Light driven by analog output LightLevel[1]. DIGITAL_INPUT TerminateFade; ANALOG_OUTPUT LightLevel[20]; PUSH TerminateFade {    SIGNED_INTEGER status;    if(IsSignalDefined(LightLevel[1]))    {       status = StopRamp(LightLevel[1]);       if(status \< 0)          GenerateUserWarning("Error stopping ramping process, status = %d", status);    } }     Version: SIMPL Version 2.10.00 or later SIMPL+ Version 3.03.00 or later 2-series only, CUZ 4.000 or later [Ramping Functions Error Codes]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Random Number Functions > Overview > Random Number Functions Overview -------------------------------------------------------------------------------- # Random Number Functions Overview These functions allow a SIMPL+ program to generate a random number. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Random Number Functions > RANDOM > Random -------------------------------------------------------------------------------- # Random Name: Random Syntax:     INTEGER Random(INTEGER LowerBound, INTEGER UpperBound); Description: Generate a random number. See also: [Seed] and [Rnd]. Parameters: LowerBound is an INTEGER specifying the lower end of the range. UpperBound is an INTEGER specifying the upper end of the range. Both LowerBound and UpperBound are treated as unsigned values. Return Value: Returns an unsigned number from LowerBound to UpperBound. Both LowerBound and UpperBound are legal values. Example:     INTEGER NUM;     FUNCTION MAIN()     {       NUM = RANDOM(25, 80);       PRINT("The random number between 25 and 80 is: %u\n", NUM);     } An example output from this would be:     The random number between 25 and 80 is: 42 Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later [Seed]: SEED.md [Rnd]: RND.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Random Number Functions > RND > Rnd -------------------------------------------------------------------------------- # Rnd Name: Rnd Syntax:     INTEGER Rnd(); Description: Generate a random number. See also: [Seed] and [Random]. Parameters: None. Return Value: An INTEGER from 0 to 65535. Example:     INTEGER NUM;     FUNCTION MAIN()     {       NUM = RND();       PRINT("The random number is: %u\n", NUM);     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later [Seed]: SEED.md [Random]: RANDOM.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Random Number Functions > SEED > Seed -------------------------------------------------------------------------------- # Seed Name: Seed Syntax:     Seed(INTEGER SeedValue); Description: Provides a seed or origin for the random number generator so that the numbers returned by RND and RANDOM are pseudo-random numbers. SEED is not required for generating random numbers as the random number generator will be seed with a default value.  This default value is issued at control system restart, not program restart.  That is, if you don't used the SEED call, you will not get the same value if you restart the program.  For any particular value of SEED, the random number generator will generate a predictable series of numbers. Note that specifying the seed value is global to all SIMPL+ programs running inside a control system. The sequence begins again whenever SEED is called. Parameters: None. Return Value: None. Example:     INTEGER NUM;     FUNCTION MAIN()     {       SEED(25);       NUM = RANDOM(25, 80);       PRINT("The random number between 25 and 80 is: %u\n", NUM);     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > MAKESTRING > MakeString -------------------------------------------------------------------------------- # MakeString Name: MakeString Syntax:     MakeString(STRING DESTINATION, \ [, \ ...]);     MakeString(0 | 1 | 2, \ [,                \ ...]); Description: MAKESTRING is a variant of [PRINT]. The output of MAKESTRING goes to the DESTINATION string. It can print simple text strings or complex formatted strings. The second form of MAKESTRING allows different destinations to be selected: 0:  Console Port, same as PRINT. 1:  CPU (same functionality as SendPacketToCPU function) 2:  Cresnet Network (same functionality as SendCresnetPacket function). NOTE:  In the second form, the first argument may not be a variable containing 0, 1, 2. It must be the written as 0, 1, 2. Crestron is discouraging the use of the second form of MAKESTRING in favor of either the PRINT command or alternate methods for activating devices that do not require knowledge of Cresnet packets, which are subject to change. Parameters: DESTINATION is a string where the output goes to after it has been formatted and processed. For a further description of formatting, refer to [PRINT]. Return Value: None. Example:     INTEGER X;     STRING Z[100], OUT[100];     X=10;     Z="Hello";     FUNCTION MAIN()     {       // Puts "This is a string" followed by a CRLF onto OUT.       MAKESTRING(OUT, "This is string\n");       // Puts "The value of X is 10 in decimal, 0A in hex"       // followed by CRLF onto OUT.       MAKESTRING(OUT, "The value of X is %u in decimal, %02X in       hex\n", X, X);       // Puts "The String value is Hello" onto OUT.       MAKESTRING(OUT, "The String value is %s", Z);     } Version: X Generation SIMPL v1.20.01 and later SIMPL v1.50.06 and later, adds Console, Cresnet, and CPU destinations. 2-Series SIMPL v2.01.05 and later, [Same as X Generation SIMPL v1.50.06], but allows %c format specifier. [PRINT]: PRINT.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > Overview > String Formatting & Printing Functions Overview -------------------------------------------------------------------------------- # String Formatting & Printing Functions Overview The printing functions are used to take INTEGER and STRING type arguments in a SIMPL+ program, format them in a user specified way, and send the output to either the CONSOLE of the control system or to another STRING. The functions are: [MakeString] [Print] [String Concatenation] [String Operators] [Trace] [MakeString]: MAKESTRING.md [Print]: PRINT.md [String Concatenation]: STRING_CONCATENATION.md [String Operators]: String_Operators.md [Trace]: TRACE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > PRINT > Print -------------------------------------------------------------------------------- # Print Name: Print Syntax:     PRINT(\ [, \ ...]); Description: The output of PRINT goes to the CONSOLE of the control system and can be monitored in the Crestron Viewport. It can print simple text strings or complex formatted strings. (See also [TRACE]) Parameters: \ is a quoted string that contains text and formatting information. Format specifiers are of the form:     %[[Pad]Width]specifier Valid format specifiers are: s:  Specifies a BUFFER_INPUT, STRING, or STRING_INPUT variable (unprintable characters are printed in the format that Viewport uses). d:  Specifies an ANALOG_INPUT, ANALOG_OUTPUT, or INTEGER to be printed as a signed decimal value. u:  Specifies an ANALOG_INPUT, ANALOG_OUTPUT, or INTEGER to be printed as an unsigned decimal value. x:  Specifies an ANALOG_INPUT, ANALOG_OUTPUT, or INTEGER to be printed as a lowercase hexadecimal number. X:  Specifies an ANALOG_INPUT, ANALOG_OUTPUT, or INTEGER to be printed as an uppercase hexadecimal number. l: Specifies a LONG_INTEGER or UNSIGNED_LONG_INTEGER will follow, and is followed by d, u, x, or X. %:  Prints a % sign (i.e. use %% to print a % sign). %ld: Specifies a LONG_INTEGER to be printed as a signed decimal value. %c: Specifies a printable ASCII character to be printed. The optional Width specifier is a number that states the width of the field as characters. If the value to be printed is less than the Width, it is padded on the left with spaces for alpha-characters and zeros for numeric characters. (Width can be two digits). The optional Pad specifier works with the Width specifier. If the result of the Width operation results in the need to add spaces, the Pad specifier can be used to pad with different values rather than a space. '0' is the only valid pad value, i.e., %03d pads with leading zeros so 1Z would be printed as 012. As each % value is found, it pulls the matching \ off the list. The first % uses \, the second % uses \, etc. If the number of % specifiers does not match the number of arguments, the program will generate a compile error. The compiler also checks to make sure the format specifier matches the type of the variable being used (i.e. if %d is used, the variable being used should be INTEGER type). NOTE:  If no format specifiers are used, then a simple quoted text string is printed. NOTE:  The total string length that can be guaranteed to print is 256 characters.  \ For example: string a[500], b[500]; a = " { A STRING WITH 200 CHARACTERS } "; b = " { A STRING WITH 56 CHARACTERS } "; print("%s%s", a,b); You would see all 256 characters. If the total adds up to greater than 256 characters, it is possible that more may be seen, but only 256 is guaranteed.  [MAKESTRING()] does not have this limitation. NOTE:  Hex sequence characters within the format specifier will be translated into the equivalent ascii character before the format specifier is translated.  For example, Print( "\x25%s", "abc" );, will NOT result in printing "%abc".  The result will be "%s" since the compiler will translate the \x25 to the % character first  (the Print statement will become Print( "%%s", "abc");) In the \, certain values may be printed using "escape sequences". Escape sequences start with the \\ character and have a variable number of characters following. The following table specifies the legal escape sequences: | | | | |--------|------------------------------------------------|--------------| | ESCAPE | MEANING | HEX CONSTANT | | \n | Carriage Return + Linefeed | \x0D\0A | | \t | Tab | \x09 | | \b | Backspace | \x08 | | \r | Carriage Return | \x0D | | \f | Form Feed | \x0C | | \a | Audible Alert (Bell) | \x07 | | \\ | Backslash | \x5C | | \\ | Single Quote | \x27 | | \\ | Double Quote | \x22 | | \xZZ | Hex Constant. Z can range from 0-9, a-f or A-F | \xZZ | Return Value: None. Example:     INTEGER X;     STRING Z[100];     X=10;     Z="Hello";     FUNCTION MAIN()     {       // Outputs "This is a string" followed by a CRLF.       PRINT("This is a string\n");       // Outputs "The value of X is 10 in decimal, 0A in hex"       // followed by CRLF.       PRINT("The value of X is %u in decimal, %02X in hex\n",       X, X);       // Outputs "The String value is Hello"       PRINT("The String value is %s", Z);     } Version: X Generation SIMPL v1.20.01 and later 2-Series SIMPL v2.01.05 and later, [Same as X Generation SIMPL v1.20.01], but allows %c format specifier. [TRACE]: TRACE.md [MAKESTRING()]: MAKESTRING.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > STRING CONCATENATION -------------------------------------------------------------------------------- # STRING CONCATENATION String concatenation can be performed either using the + operator or by using MAKESTRING or PRINT functions. It is easier to use the + operator in general usage, although the formatting options of the MAKESTRING and PRINT functions give greater flexibility. The + operator for strings is used the same way as in mathematical expressions. String concatenation may only be used as a standalone statement. The syntax is: \ = \ [+ \ ...]; When string values appear on the right-side of the equal sign, the exact contents are appended to the new string. \ values may be of type literal (quoted) strings, BUFFER_INPUT, STRING, STRING_INPUT, or any function that returns a string. Examples: INTEGER I; INTEGER J;     STRING A$[100], B$[100], C$[100];     B$="Hello";     C$="World!";     I=56;     J=2;     // This will output "Hello562xyzWorld!"     A$=B$+ITOA(I)+ITOA(J)+"xyz"+C$;     PRINT("%s", A$);     // This will output "8Hello2World"     A$=CHR(I)+B$+ITOA(J)+C$;     PRINT("%s", A$); -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > String Operators -------------------------------------------------------------------------------- # String Operators String Operators | | | | | |----------|--------------|--------------|-------------------------------------| | OPERATOR | NAME | EXAMPLE | EXPLANATION | | = | Assignment | A$ = B$ | Assigns the contents in B$ to A$. | | = | 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. The comparison "ABC" \< "ABCD" is true, because a shorter string alphabetically precedes one that is identical but longer. -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Formatting & Printing Functions > TRACE -------------------------------------------------------------------------------- # TRACE Name: Trace Syntax:     TRACE(\ [, \ ...]); Description: The output of TRACE goes to the CONSOLE of the control system and can be monitored in the Trace window in the Crestron Toolbox SIMPL Debugger and in Crestron Viewport. It can display simple text strings or complex formatted strings. NOTE: PRINT() and TRACE() are equivalent, with the exception that TRACE prepends the hex  characters \xFA\xE0, and suffixes the string with \xFB - and with the exception of how the  compiler directives #ENABLE_TRACE and #PRINT_TO_TRACE deal with the print() and trace() statements. See also [Print] and [#ENABLE_TRACE] and [#PRINT_TO_TRACE] for more information. Version: 2-Series SIMPL v2.10.09 and later, [Same as X Generation SIMPL v1.20.01], but allows %c format specifier. [Print]: PRINT.md [#ENABLE_TRACE]: ../Compiler_Directives/_ENABLE_TRACE.md [#PRINT_TO_TRACE]: ../Compiler_Directives/_PRINT_TO_TRACE.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > CLEARBUFFER > ClearBuffer -------------------------------------------------------------------------------- # ClearBuffer Name: ClearBuffer Syntax:     ClearBuffer(STRING BUFFERNAME); Description: Deletes the contents of the specified buffer. If a LEN is done on the buffer after a CLEARBUFFER, the return value will be 0. This is equivalent to assigning an empty string to the buffer, e.g., BUFFERNAME=""; Parameters: BUFFERNAME specifies the name of the string to empty. BUFFER_INPUT, STRING, and STRING_INPUT sources are legal. Return Value: None. Example:     BUFFER_INPUT IN$[100];     CHANGE IN$     {       IF(RIGHT$(IN$,1) = "Z")         CLEARBUFFER(IN$);       // Code to process IN$ goes here.     } In this example, if the last character that comes into the BUFFER_INPUT is "Z", the buffer is cleared. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > CompareStrings -------------------------------------------------------------------------------- # CompareStrings Name: CompareStrings Syntax:     SIGNED_INTEGER CompareStrings(STRING string1, STRING string2); Description: Performs a case-sensitive comparison of string1 and string2.  This function can be used in place of the "=", "\<", "\>", "\<\>" operators. The comparison is done in ASCII order (e.g., the string "ABC" is less than "ABD" and the string "abc" is greater than "ABC" since the character 'a' comes after 'A' in the ASCII table). Parameters: STRING string1:  First string to use in the comparison STRING string2:  Second string to use in the comparison Return Value: \< 0: indicates that string1 is less than string2 in ASCII order. 0: indicates that string1 is equal to string2 in ASCII order. \> 0: indicates that string1 is greater than string2 in ASCII order. Example:     STRING FirstString, SecondString;     SIGNED_INTEGER result;     FirstString = "ValueA";     SecondString = "Valueb";     result = CompareStrings(FirstString, SecondString);     Print("Result is %d.\n", result); Since the first 5 characters are the same, the result comes down to comparing 'A' and 'b'.  Since the ASCII value of 'b' (0x62) is greater than the ASCII value of 'A' (0x41), the result is string1 \> string2.  The output of the function is –1, so the Print statement prints: "Result is 1." Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > CompareStringsNoCase -------------------------------------------------------------------------------- # CompareStringsNoCase Name: CompareStringsNoCase Syntax:     SIGNED_INTEGER CompareStringsNoCase(STRING string1, STRING string2); Description: Performs a case-insensitive comparison of string1 and string2. The strings are internally converted to uppercase before the comparison is done.  The original strings passed into the function are not modified.  The comparison is done in ASCII order. (e.g., the string "ABC" is less than "ABD" however the string "AbC" and "aBC" are the same, since the comparison is case insensitive). Parameters: STRING string1:  First string to use in the comparison STRING string2:  Second string to use in the comparison Return Value: -1: indicates that string1 is less than string2 in ASCII order. 0: indicates that string1 is equal to string2 in ASCII order. 1: indicates that string1 greater than string2 in ASCII order. Example:     STRING FirstString, SecondString;     SIGNED_INTEGER result;     FirstString = "Valuea";     SecondString = "Valueb";     result = CompareStringsNoCase(FirstString, SecondString);     Print("Result is %d.\n", result); The strings are internally converted to "VALUEA" and "VALUEB".  Since the first 5 characters are the same, the result comes down to comparing 'A' and 'B'.  Since the ASCII value of 'A' (0x41) is less than the ASCII value of 'B' (0x42), the result is string1 \< string2.  The output of the function is –1, so the Print statement prints: "Result is –1." Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > FIND > Find -------------------------------------------------------------------------------- # Find Name: Find Syntax:     INTEGER Find(STRING MATCH_STRING, STRING SOURCE_STRING                  [,INTEGER START_POSITION]); Description: Finds the position in SOURCE_STRING where MATCH_STRING first occurs. The search is case sensitive. Parameters: MATCH_STRING is a STRING containing the string to be matched. SOURCE_STRING is a STRING containing the string to be searched. START_POSITION is an INTEGER which tells FIND at what character in the string to start the search, and is 1 based. If it is not specified, it defaults to 1. Return Value: The index of where MATCH_STRING first occurs (going left to right) in SOURCE_STRING. If a match can not be found, or POSITION exceeds the length of the SOURCE_STRING then 0 is returned. The index is 1 based. Example:     STRING_INPUT IN$[100];     INTEGER START_LOC;     CHANGE IN$     {       START_LOC = FIND("XYZ", IN$);       PRINT("XYZ was found starting at position %d in %s\n",       START_LOC, IN$);     } If IN$ was set equal to "Hello, World!" then START_LOC would be 0 since "XYZ" can not be found. If IN$ was equal to "CPE1704XYZXYZ", then START_LOC would be equal to 8. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > FindNoCase -------------------------------------------------------------------------------- # FindNoCase Name: FindNoCase Syntax:     INTEGER FindNoCase(STRING MATCH_STRING, STRING SOURCE_STRING                  [,INTEGER START_POSITION]); Description: Finds the position in SOURCE_STRING where MATCH_STRING first occurs. The search is case insensitive. Parameters: MATCH_STRING is a STRING containing the string to be matched. SOURCE_STRING is a STRING containing the string to be searched. START_POSITION is an INTEGER which tells FINDNOCASE at what character in the string to start the search, and is 1 based. If it is not specified, it defaults to 1. Return Value: The index of where MATCH_STRING first occurs (going left to right) in SOURCE_STRING. If a match can not be found, or POSITION exceeds the length of the SOURCE_STRING then 0 is returned. The index is 1 based. Example:     STRING_INPUT IN$[100];     INTEGER START_LOC;     CHANGE IN$     {       START_LOC = FINDNOCASE("XYZ", IN$);       PRINT("XYZ was found starting at position %d in %s\n",       START_LOC, IN$);     } If IN$ was set equal to "Hello, World!" then START_LOC would be 0 since "XYZ" can not be found. If IN$ was equal to "CPE1704XYZXYZ", then START_LOC would be equal to 8. Version: SIMPL+ Version 3.03.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GATHER > Gather -------------------------------------------------------------------------------- # Gather Name: Gather Syntax:     STRING Gather(STRING Delimiter, STRING SourceString [INTEGER TimeOut]); Description: Concatenates the data from SourceString and issues it on the return string when the specified delimiter has been reached. At that time, the data will be removed from SourceString. Note that when Gather is executed, if SourceString does not include the Delimiter, then the equivalent of a PROCESSLOGIC is performed. When the system returns to the Gather, it will once again check for the proper delimiter. In effect, a section of code (a CHANGE statement, for example) is held up at the Gather until the proper data is received. The optional Timeout parameter will provide a way for the function to transfer control back to the module when the specified time allows. If the Timeout parameter is specified, then the length of the return string should be checked to determine if a Timeout has occurred (length = 0). Parameters: Delimter is a string containing the terminating sequence of characters in the desired string. SourceString is the string from which to remove the sequence of characters ending in the desired sequence. Timeout is an integer specifying the timeout period in 1/100ths of a second. NOTE:  It makes sense only to use Gather with STRING_INPUT or BUFFER_INPUT types. Return Value: The returned string includes concatenated data from SOURCESTRING and  the STRING DELIMITER. Example:     BUFFER_INPUT COM$[100];     DIGITAL_INPUT trig;     STRING IN$[100];     PUSH trig     {       IN$ = GATHER("\n", COM$);       PRINT("The value of IN$ is %s\n", IN$);     } In this example, the event is started when TRIG goes high. When data comes into COM$, the GATHER statement is evaluated. The PRINT statement is never reached until the delimiter \n (CRLF) is found. When the delimiter is found, then the string will be printed. Note that the GATHERed string will have the \n on it. Example:     BUFFER_INPUT COM$[100];     DIGITAL_INPUT trig;     STRING IN$[100];     CHANGE COM$     {       IN$ = GATHER("\n", COM$);       PRINT("The value of IN$ is %s\n", IN$);     } If, in the first event, COM$ contains the string "Hello", the event will wait in the GATHER. When the COM$ changes again to contain " World!\n", the event will immediately resume after the GATHER. The CHANGE COM$ event will only be called once in this case. In the X-Generation Control Systems, the CHANGE event would be called both times. In the 2-Series Control System processors, a GATHER that is waiting for data will use up the next changes in the BUFFER_INPUT until the terminating character is encountered. That is, any CHANGE event handler for the BUFFER_INPUT will not be called.   Version: SIMPL+ Version 3.03.00 or later CUZ3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GETC > GetC -------------------------------------------------------------------------------- # GetC Name: GetC Syntax:     INTEGER GetC(BUFFER_INPUT SOURCE); Description: Returns the value at position 1 of SOURCE string and shifts the rest of the buffer up by one. In this way, values may be picked out of a buffer for processing. Parameters: SOURCE is typically from a BUFFER_INPUT statement. It may be defined as a STRING or STRING_INPUT, but since GETC removes characters from SOURCE, the result is destructive to the source string. Return Value: An INTEGER containing a single character from position 1 of the buffer. If there are no characters in the buffer for GETC to retrieve, then the value of 65535 is returned. Example: In this example, a buffer input is read until the character "A" is retrieved.     BUFFER_INPUT IN$[100];     INTEGER INCHAR;     CHANGE IN$     {       INCHAR = 0;       WHILE(INCHAR \<\> 'A')         INCHAR = GETC(IN$);       // continue processing.     } Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherAsync -------------------------------------------------------------------------------- # GatherAsync Name: GatherAsync Syntax:     [SIGNED_INTEGER] GatherAsync (STRING Delimiter, BUFFER_INPUT Input, GatherEventHandler EventHandler, [INTEGER Timeout]); Description: Receives BUFFER_INPUT data and flags it as waiting for a gather operation. When new data comes in from the logic engine, the match criteria will be evaluated.  If the condition is met,  i.e. specific sequence of characters is received, a thread will be triggered to invoke the  callback function, thus eliminating the need for a separate thread waiting on each input, as each threads will only be active when there is work to be done. If the Timeout parameter is specified and the match condition has not been met before this time expires, the callback function is invoked with a result code of timeout. Parameters: Delimiter is a specific sequence of characters that marks the end of the desired data Input is a BUFFER_INPUT variable that will receive data coming into the SIMPL+ module. EventHandler is the callback function which is invoked when the Delimiter is found Timeout is an optional INTEGER parameter which specifies the timeout period (n 1/100ths of a second.) after which the callback function will be called and the result code in the [GatherEventArgs] parameter will be set to -1. Return Value: Returned value provides information about the status of the gather operation, as follows: | | | |--------------|------------------------------------------------| | Return Value | Description | | 0 | Success | | \<0 | Error occurred | | -1 | Problem with one of the parameters | | 1 | Success, but replacing previously set criteria | Example: DIGITAL_INPUT ByDelimiter; PUSH ByDelimiter { GatherAsync(“\n”, MyInput, MyGatherCallback); } In this example, the event is triggered when the DIGITAL_INPUT ByDelimiter goes high. Data coming into MyInput is gathered until finding the delimiter '\n'.  After the delimiter is found,  MyGatherCallback is executed with the gathered data (including the delimiter) as an argument. Version: SIMPL+ Version 4.04.01 or later required [GatherEventArgs]: GatherEventArgs.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherAsyncByLength -------------------------------------------------------------------------------- # GatherAsyncByLength Name: GatherAsyncByLength Syntax:      [SIGNED_INTEGER] GatherAsyncByLength (INTEGER NumCharsToMatch, BUFFER_INPUT input, GatherEventHandler EventHandler, [INTEGER Timeout]); Description: Receives BUFFER_INPUT data and flags it as waiting for a gather operation. When new data comes in from the logic engine, the match criteria will be evaluated.  If the condition is met,  i.e. number of bytes specified in INTEGER NumCharsToMatch is received, a thread will be triggered to invoke the callback function, thus eliminating the need for a separate thread waiting on each input, as each threads will only be active when there is work to be done. If the optional Timeout parameter is specified and the match condition has not been met before this time expires, the callback function is invoked with a result code of timeout. Parameters: NumCharsToMatch is an integer specifying the number of desired characters before executing the callback function Input is a BUFFER_INPUT variable that will receive data coming into the SIMPL+ module. EventHandler is the callback function which is invoked when the Delimiter is found Timeout is an optional integer parameter which specifies the timeout period (n 1/100ths of a second.) after which the callback function will be called and the result code in the GatherEventArgs parameter will be set to -1. Return Value: Returned value provides information about the status of the gather operation, as follows: | | | |--------------|------------------------------------------------| | Return Value | Description | | 0 | Success | | \<0 | Error occurred | | -1 | Problem with one of the parameters | | 1 | Success, but replacing previously set criteria | Example:     DIGITAL_INPUT ByLength;     PUSH ByLength { GatherAsyncByLength(40, MyInput, MyGatherByLengthCallback); } In this example, the event is triggered when the DIGITAL_INPUT ByLength goes high. Data coming into MyInput is gathered until the number of character reaches 40 and then  MyGatherCallback is executed with the gathered data as an argument. Version: SIMPL+ Version 4.04.01 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherByLength > GatherByLength -------------------------------------------------------------------------------- # GatherByLength Name: GatherByLength Syntax:      STRING GatherByLength(INTEGER NumBytes, STRING SourceString [INTEGER Timeout]); Description: Concatenates the data from SourceString and issues it on the return string when the specified number of bytes have been reached. At that time, the data will be removed from SourceString. Note that when GatherByLength is executed, if SourceString does not include the specified number of bytes, then the equivalent of a PROCESSLOGIC is performed. When the system returns to the GatherByLength, it will once again check for the specified number of bytes (INTEGER NumBytes). In effect, a section of code (a CHANGE statement, for example) is held up at the GatherByLength until the specified NumBytes  is received. The optional Timeout parameter will provide a way for the function to transfer control back to the module when the specified time allows. If the Timeout parameter is specified, then the length of the return string should be checked to determine if a Timeout has occurred (length = 0). Parameters: NumBytes is an integer specifying the number of characters to be removed from the SourceString. SourceString is the string from which to remove the sequence of characters ending in the desired sequence. Timeout is an integer specifying the timeout period in 1/100ths of a second. NOTE:  It makes sense only to use GatherByLength with STRING_INPUT or BUFFER_INPUT types. Return Value: The length of the returned string is the NumBytes specified. Example:     BUFFER_INPUT COM$[100];     DIGITAL_INPUT trig;     STRING IN$[100];     PUSH trig     {       IN$ = GATHERBYLENGTH(2, COM$);       PRINT("The value of IN$ is %s\n", IN$);     } In this example, the event is started when TRIG goes high. When data comes into COM$, the GatherByLength statement is evaluated. The PRINT statement is never reached until the number of bytes, NumBytes, is obtained. When the total number of bytes specified is obtained, then the string will be printed. Example:     BUFFER_INPUT COM$[100];     DIGITAL_INPUT trig;     STRING IN$[100];     CHANGE COM$     {       IN$ = GATHER(2, COM$);       PRINT("The value of IN$ is %s\n", IN$);     } If, in the first event, COM$ contains the string "Hello", the event will wait in the GATHERBYLENGTH. When the COM$ changes again to contain " World!\n", the event will immediately resume after the GATHERBYLENGTH. The CHANGE COM$ event will only be called once in this case. In the 2-Series Control System processors, a GATHERBYLENGTH that is waiting for data will use up the next changes in the BUFFER_INPUT until the number of bytes is obtained. That is, any CHANGE event handler for the BUFFER_INPUT will not be called.   Example: #DEFINE_CONSTANT GATHERBYLENGTH_TIMEOUT 200 // 2 second timeout BUFFER_INPUT MyLengthString[1000]; CHANGE MyDelimitedString {    STRING LocalString[256];    While (1)    {      LocalString = GatherByLength(2, MyDelimitedString, GATHER_TIMEOUT);      If (Len(LocalString) = 0) // timeout occurred      {        ClearBuffer(MyDelimitedString);        Print("Timeout occurred in Delimited string. \n");        Break;      }      // code to work with received string    }  }  CHANGE MyLengthString  {    STRING LocalString[256];    While (1)    {      LocalString = GatherByLength(20, MyLengthString, GATHER_TIMEOUT);      If (Len(LocalString) = 0) // timeout occurred      {        ClearBuffer(MyLengthString);        Print("Timeout occurred in Length string. \n");        Break;      }      // code to work with received string    }  } In this example, GatherByLength would continue to remove the specified number of bytes in MyLengthString until it was empty, which would cause a timeout. Version: SIMPL+ Version 3.03.00 or later CUZ3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherByLengthWithDest -------------------------------------------------------------------------------- # GatherByLengthWithDest Name: GatherByLengthWithDest Syntax:     [SIGNED INTEGER] GatherByLengthWithDest(INTEGER NumCharsToMatch, BUFFER_INPUT Input, STRING Destination [,INTEGER Timeout]); Description: Concatenates the data from the BUFFER INPUT string into the destination string parameter till the specified number of characters has been reached.  In effect, GatherByLengthWithDest is a version of the traditional [GatherByLength] function that holds the result of the gather operation in the destination string parameter, thus improving the operational speed of GatherByLengthWithDest over the speed of the [GatherByLength] function. Note that similarly to the traditional [GatherByLength] function, GatherByLengthWithDest is a blocking operation i.e. the thread will stop executing until the gather condition is satisfied or the optional timeout expires. Parameters: NumCharsToMatch is an integer specifying the number of desired characters. Input is a BUFFER_INPUT variable that will receive data coming into the SIMPL+ module. Destination is the destination string which will hold the result of the gather operation. Timeout is an optional INTEGER parameter that allows the thread to continue to execute if the gather conditions are not met within the specified timeout period (in 1/100ths of a second.). Return Values: | | | |----|----| | Return Value | Description | | 0 | Success | | \<0 | Error occurred | | -1 | Timeout occurred | | -2 | Resource conflict.  Two threads are trying to access the same BUFFER_INPUT at the same time. | Example:     BUFFER_INPUT MyInput[256];     DIGITAL_INPUT trig;     STRING dest[80]; PUSH trig {    Signed_Integer Status;    Status = GatherByLengthWithDest(24, MyInput, dest);    PRINT ("The Value of dest is %s\n", dest);      } In this example, the event is triggered when the DIGITAL_INPUT trig goes high. Data coming into MyInput is gathered until the specified number of characters has been reached.  After that,  the destination string will be printed. Version: SIMPL+ Version 4.05.01 or later [GatherByLength]: GatherByLength.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherEventArgs -------------------------------------------------------------------------------- # GatherEventArgs Name: GatherEventArgs Description: GatherEventArgs is a structure which is used to hold data about the gather operation and pass that data to the [GatherEventHandler]. GatherEventArgs has the following format: STRUCTURE GatherEventArgs { STRING RxString; SIGNED_INTEGER Results; BUFFER_INPUT Input; } Field/Members: RxString is the string resulting from the [GatherAsync] or [GatherAsyncByLength].  If a delimiter is specified in the [GatherAsync] call, then the delimiter is included in the string. Results is the an integer representing the status of the gather operation. Possible values are:               0:  Success              -1: Timeout occurred. Input is the buffer input associated with the [GatherAsync] or [GatherAsyncByLength]. This buffer input is used by the callback in the [RearmGatherAsync] call. Example:     callback GatherEventHandler MyGatherCallback(GatherEventArgs Args) { if (Args.RESULTS = 0) { Print(" Received Message: %s", Args.RXSTRING); } else Print("Timeout in GatherAsync\n"); } In this example, the GatherEventArgs structure is passed as an argument of [GatherEventHandler]. The result of the gather operation Args.RESULTS is evaluated and the first PRINT statement is executed to print the string Args.RXSTRING. In case of a timeout (Args.RESULTS = -1), the second PRINT statement is executed. Version: SIMPL+ Version 4.04.01 or later required [GatherEventHandler]: GatherEventHandler.md [GatherAsync]: GatherAsync.md [GatherAsyncByLength]: GatherAsyncByLength.md [RearmGatherAsync]: RearmGatherAsync.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > GatherEventHandler -------------------------------------------------------------------------------- # GatherEventHandler Name: GatherEventHandler Syntax:     callback GatherEventHandler myCallBack(GatherEventArgs args); Description: GatherEventHandler is a callback function that is supplied as an argument to [GatherAsync] or [GatherAsyncByLength], such that the GatherEventHandler is invoked when the match criteria in [GatherAsync] or [GatherAsyncByLength] are met. Parameters: Args is a structure of type [GatherEventArgs] containing data from the gather operation.. Example:     callback GatherEventHandler MyGatherCallback(GatherEventArgs Args) { if (Args.RESULTS = 0) { Print("Got Message: %s", Args.RXSTRING); RearmGatherAsync(Args.INPUT); } else Print("Got a timeout in GatherAsync\n"); } Version: SIMPL+ Version 4.04.01 or later required [GatherAsync]: GatherAsync.md [GatherAsyncByLength]: GatherAsyncByLength.md [GatherEventArgs]: GatherEventArgs.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > LEFT > Left -------------------------------------------------------------------------------- # Left Name: Left Syntax:     STRING Left(STRING SOURCE, INTEGER NUM); Description: Takes the leftmost NUM characters of SOURCE and returns them in an output string. Parameters: SOURCE is a STRING containing the source string. NUM is an INTEGER that tells LEFT how many characters to use in the computation. Return Value: A string representing the leftmost NUM characters of SOURCE. If NUM is greater than the number of characters in SOURCE, then the return is identical to SOURCE. Example:     STRING_INPUT Var$[100];     STRING Temp$[100];     CHANGE Var$     {       Temp$ = LEFT(Var$, 5);         PRINT("Left most 5 characters of %s are %s\n", Var$, Temp$);     } In this example, if  Var$ is "abcdefghijk",  Temp$ will contain "abcde". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > LEN > Len -------------------------------------------------------------------------------- # Len Name: Len Syntax:     INTEGER Len(STRING SOURCE); Description: Returns the actual length of the string, not the declared maximum length. Parameters: SOURCE is a string whose length is to be determined. Return Value: A value from 0 - 65535, which gives the number of characters in the string. An empty string returns a length of 0. Example:     STRING_INPUT IN$[100];     INTEGER Temp;     CHANGE IN$     {       Temp = LEN(IN$);       PRINT("The Length of %s is %d\n", IN$, Temp);     } In this example, if IN$ is equal to "This is a test" then Temp will contain the integer 14. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > LOWER > Lower -------------------------------------------------------------------------------- # Lower Name: Lower Syntax:     STRING Lower(STRING SOURCE); Description: Takes a source string and converts characters with the values A-Z (uppercase) to a-z (lowercase). Parameters: SOURCE is a string to be converted to lowercase. SOURCE is not modified, unless it is also used as the return value, e.g., S$=LOWER(S$); Return Value: A STRING containing the lowercase version of SOURCE. Characters that do not fall into the range A-Z are not modified and will stay as specified. You can use the same variable for both the argument and return. e.g., s$=lower(s$); Example:     STRING_INPUT IN$[100];     STRING LOWER$[100];     CHANGE IN$     {       LOWER$ = LOWER(IN$);       PRINT("Lowercase version of %s is %s\n",IN$, LOWER$);     } In this example, if IN$ contains "This is a Test123!", then LOWER$ will contain "this is a test123!". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > MID > Mid -------------------------------------------------------------------------------- # Mid Name: Mid Syntax:     STRING Mid(STRING SOURCE, INTEGER START, INTEGER NUM); Description: Returns a string NUM characters long from SOURCE, starting at position START. Parameters: SOURCE is a STRING containing the input string. START is an INTEGER telling MID at which character position in SOURCE to start. The first character of SOURCE is considered 1. NUM is an INTEGER telling MID how many characters to use from SOURCE. Return Value: A string NUM characters long starting at START. If START is greater than the length of SOURCE, an empty STRING is returned. If NUM is greater than the total number of characters that can be retrieved starting from START, only the remaining characters in SOURCE will be pulled. For example, MID("ABCD", 2, 10) would return a STRING containing BCD. Example:     STRING_INPUT Var$[100];     STRING Temp$[100];     CHANGE Var$     {       Temp$ = MID(Var$, 2, 5);         PRINT("String starting at position 2 for 5 characters is %s\n",             Temp$);     } In this example, if Var$ contains "abcdefghijklmnop", then Temp$ will contain "bcdef". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > Overview > String Parsing and Manipulation Functions Overview -------------------------------------------------------------------------------- # String Parsing and Manipulation Functions Overview String parsing and manipulation functions are used where the contents of string variables need to be examined or modified. | Function | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ClearBuffer | Deletes the contents of the specified buffer. | | CompareStrings | Performs a case-sensitive comparison of two strings. | | CompareStringsNoCase | Performs a case-insensitive comparison of two strings. | | Find | Finds the position in SOURCE_STRING where MATCH_STRING first occurs. Search is case sensitive. | | FindNoCase | Finds the position in SOURCE_STRING where MATCH_STRING first occurs. The search is case insensitive. | | Gather | Concatenates the data from SOURCESTRING and issues it on the return string when the specified delimiter has been reached. | | GatherAsync | Concatenates the data from the BUFFER INPUT string into the destination string parameter until specific sequence of characters is received | | GatherAsyncByLength | Concatenates the data from the BUFFER INPUT string until the number of bytes specified in NumCharsToMatch is received, | | GatherByLength | Concatenates the data from SourceString and issues it on the return string when the specified number of bytes have been reached. | | GatherByLengthWithDest | Concatenates the data from the BUFFER INPUT string into the destination string parameter till the specified number of characters has been reached. | | GetEncoding | Returns the encoding of a string. The following constants are declared to help comparison: ENCODING_ASCII – Returned when the encoding of the string is set to ASCII ENCODING_UTF16 – Returned when the encoding of the string is set to UTF16 Any other return value should be treated as an error. | | Left | Takes the leftmost NUM characters of SOURCE and returns them in an output string. | | Len | Returns the actual length of the string, not the declared maximum length. | | Lower | Takes a source string and converts characters with the values A-Z (uppercase) to a-z (lowercase). | | Mid | Returns a string NUM characters long from SOURCE, starting at position START. | | RearmGatherAsync | Resets the Gather trigger to the criteria used in the previous match | | Remove | Begins searching a string for the at the specified position, then removes all characters from the beginning of the string up to and including the delimiter. | | RemoveByLength | Removes all characters from the beginning of the SOURCESTRING up to the NumBytes specified and returns a string containing the number of bytes removed | | RemoveGatherAsync | Removes the specified the BUFFER INPUT serial data from the gather operation. | | ResizeString | Changes the allocated size of the string to NewSize bytes. | | ReverseFind | Finds the position in SOURCE_STRING where MATCH_STRING last occurs. Case sensitive. | | ReverseFindNoCase | Finds the position in SOURCE_STRING where MATCH_STRING last occurs. Case insensitive. | | Right | Takes the rightmost NUM characters of SOURCE and returns them in an output string. | | SetEncoding | Converts the encoding of a UTF16 string to ASCII. | | SetString | Overwrites the bytes in DESTINATION with the bytes in SOURCE starting at POSITION in the DESTINATION string. | | ToASCII | Converts the encoding of a UTF16 string to ASCII. | | ToUTF16 | Converts the encoding of the string to UTF16. | | Upper | Takes a source string and converts characters with the values a-z (lowercase) to A-Z (uppercase). | -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > REMOVE > Remove -------------------------------------------------------------------------------- # Remove Name: Remove Syntax:     STRING Remove(STRING DELIMITER, STRING SOURCESTRING, [INTEGER STARTPOS]); Description: Begins searching a string \ for the \ at the specified starting position \, then removes all characters from the beginning of the string \ up to and including the delimiter. Returns a string containing all of the removed characters. Parameters: DELIMITER is a string containing the terminating sequence of characters in the desired string. SOURCESTRING is the string the Remove function is performed on. Characters up to and including the DELIMITER are removed and returned as a string. STARTPOS is the starting position in the \ to start searching for the \.  It is 1 based. The first byte of \ is at position 1. Return Value: A string including the delimiter. Example:     BUFFER_INPUT SOURCE$[50];     STRING OUTPUT$[50];     CHANGE SOURCE$     {       OUTPUT$ = REMOVE("abc", SOURCE$);     } In this example, if SOURCE$ were "testabc123", then OUTPUT$ would be "testabc" and SOURCE$ would contain "123".     BUFFER_INPUT SOURCE$[50];     STRING OUTPUT$[50];     CHANGE SOURCE$     {       OUTPUT$ = REMOVE("abc", SOURCE$, 6);     } If SOURCE$ were "testabcabc123", then OUTPUT$ would be "testabcabc" and SOURCE$ would contain "123". Version: SIMPL+ Version 3.02.02 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > REVERSEFIND -------------------------------------------------------------------------------- # REVERSEFIND Name: ReverseFind Syntax:     INTEGER ReverseFind(STRING MATCH_STRING, STRING SOURCE_STRING                         [, INTEGER START_POSITION]); Description: Finds the position in SOURCE_STRING where MATCH_STRING last occurs.  The search is case-sensitive. Parameters: MATCH_STRING is a STRING containing the searched for data. SOURCE_STRING is a STRING containing the data to be searched. START_POSITION is an INTEGER which tells REVERSEFIND at what character in the string to start the search, and is 1 based. If it is not specified, it defaults to the end of the string. Return Value: The index of where MATCH_STRING last occurs (going right to left) in SOURCE_STRING. If the data can not be found, or POSITION exceeds the length of the SOURCE_STRING then 0 is returned. The index is 1 based. Example:     STRING_INPUT IN$[100];     INTEGER START_LOC;     CHANGE IN$     {       START_LOC = REVERSEFIND("XYZ", IN$);       PRINT("last XYZ occurrence was found at position %d in %s\n", START_LOC, IN$);     } If IN$ was set equal to "Hello, World!" then START_LOC would be 0 since "XYZ" can not be found. If IN$ was equal to "CPE1704XYZXYZ", then START_LOC would be equal to 11. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > RIGHT > Right -------------------------------------------------------------------------------- # Right Name: Right Syntax:     STRING Right(STRING SOURCE, INTEGER NUM); Description: Takes the rightmost NUM characters of SOURCE and returns them in an output string. Parameters: SOURCE is a STRING containing the source string. NUM is an INTEGER that tells RIGHT how many characters to use in the computation. Return Value: A string representing the rightmost NUM characters of SOURCE. If NUM is greater than the number of characters in SOURCE, then the return is identical to SOURCE. Example:     STRING_INPUT Var$[100]     STRING Temp$[100];     CHANGE Var$     {       Temp$ = RIGHT(Var$, 5);         PRINT("Right most 5 characters of %s are %s\n", Var$, Temp$);     } In this example, if Var$ contains "abcdefghijk", then Temp$ contains "ghijk". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > RearmGatherAsync -------------------------------------------------------------------------------- # RearmGatherAsync Name: RearmGatherAsync Syntax:     SIGNED_INTEGER RearmGatherAsync (BUFFER_INPUT Input); Description: Resets the Gather trigger to the criteria used in the previous match. When criteria in [GatherAsync] or [GatherAsyncByLength]. is met,  the callback function [GatherEventHandler] will be triggered once. If a further match is desired, the RearmGatherAsync function has to be called as the end line of [GatherEventHandler]. Parameters: Input is the buffer input associated with the [GatherAsync] or [GatherAsyncByLength]. Return Value: Returned value provides information about the status of the gather operation, as follows: | | | |----|----| | Return Value | Description | | 0 | Success | | \<0 | Error occurred | | -1 | There was no previous gather operation for the specified BUFFER_INPUT | Example:     callback GatherEventHandler MyGatherCallback(GatherEventArgs Args) { if (Args.RESULTS = 0) { RearmGatherAsync(Args.INPUT); } else ... } In this example, the callback function, the RearmGatherAsync is called so to utilize the same gather criteria that was used in the previous gather operation. Version: SIMPL+ Version 4.04.01 or later required [GatherAsync]: GatherAsync.md [GatherAsyncByLength]: GatherAsyncByLength.md [GatherEventHandler]: GatherEventHandler.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > RemoveByLength -------------------------------------------------------------------------------- # RemoveByLength Name: RemoveByLength Syntax:     STRING RemoveByLength(INTEGER NUMBYTES, STRING SOURCESTRING); Description: Removes all characters from the beginning of the string \ up to the NumBytes specified. Returns a string containing the number of bytes removed. Parameters: SOURCESTRING is the string the RemoveByLength function is performed on. Characters up to the NumBytes are removed and returned as a string. NUMBYTES is an integer specifying the number of characters to be removed from a SOURCESTRING. The bytes are removed starting at the first character (position 1) in the \ is 0, a string of length 0 is returned. If the length of \ is \<  \, then \ is not modified and a string of 0 length will be returned. If the length of \ is \>= \, then the first \ of \ will be returned.  \ is left with the rightmost LEN(\)-\ characters. Example:     BUFFER_INPUT SOURCE$[50];     STRING OUTPUT$[50];     CHANGE SOURCE$     {       OUTPUT$ = REMOVEBYLENGTH(2, SOURCE$);     } In this example, if SOURCE$ were "testabc123", then OUTPUT$ would be "te" and SOURCE$ would contain "stabc123". Version: SIMPL+ Version 3.02.05 or later CUZ 3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > RemoveGatherAsync -------------------------------------------------------------------------------- # RemoveGatherAsync Name: RemoveGatherAsync Syntax:     SIGNED_INTEGER RemoveGatherAsync (BUFFER_INPUT Input); Description: Removes/un-registers the specified BUFFER_INPUT serial data from the gather operation. Parameters: Input is the BUFFER_INPUT associated with [GatherAsync] or [GatherAsyncByLength]. Return Value: Returned value provides information about the status of the gather operation, as follows: | | | |----|----| | Return Value | Description | | 0 | Success | | \<0 | Error occurred | | -1 | There was no previous gather operation for the specified BUFFER_INPUT | Example:     DIGITAL_INPUT StopGather;     BUFFER_INPUT MyInput[256]; PUSH StopGather { RemoveGatherAsync(MyInput); } In this example, when DIGITAL_INPUT StopGather goes high the BUFFER_INPUT MyInput is removed from the Gather operation. Version: SIMPL+ Version 4.04.01 or later [GatherAsync]: GatherAsync.md [GatherAsyncByLength]: GatherAsyncByLength.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > ResizeString -------------------------------------------------------------------------------- # ResizeString Name: ResizeString Syntax:     SIGNED_INTEGER ResizeString (STRING StringVar, INTEGER NewSize); Description: Changes the allocated size of the string to NewSize bytes. NOTE: To use this function, the [#ENABLE_DYNAMIC] compiler directive must be present in the SIMPL+ module and the variable must be declared as [DYNAMIC]. Parameters: StringVar is the string variable that needs a change in the allocated size. NewSize indicates the new number of bytes in the string. Return Value: | | | |----------|----------------------------------| | Status | Definition | | 0 | Success | | 0x8001 | Generic Error | | 0x8002 | Error – Max Resize limit reached | | 0x8004\* | Error – Element is not dynamic | | 0x8008 | Warning – Truncation will occur | | 0x8010 | Error – Out of memory | | 0x8020 | Error – Out of memory | | 0x8040 | Error – Out of memory | \* This error indicates that the #ENABLE_DYNAMIC compiler directive is missing from the SIMPL+ module and/or that the variable has not been declared as DYNAMIC. NOTE:  The status might contain an error and a warning returned together. For example, if a string is resized from 20 to 10 characters, a truncation warning will result. However, if the system is out of memory, the resize cannot be completed. In this scenario, the returned status will be 0x8008 | 0x8010,  or 0x8018. Example:     DYNAMIC STRING MyString[10];     Function main()     {          SIGNED_INTEGER Status;          Status = ResizeString(MyString, 200);          If (status != 0)               Print("Error occurred in resizing string MyString\n")     } Version: 2 Series only X Gen not supported [#ENABLE_DYNAMIC]: javascript:void(0); [DYNAMIC]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > ReverseFindNoCase -------------------------------------------------------------------------------- # ReverseFindNoCase Name: ReverseFindNoCase Syntax:     INTEGER ReverseFindNoCase(STRING                         [, INTEGER START_POSITION]); Description: Finds the position in SOURCE_STRING where Parameters: MATCH_STRING is a STRING containing the searched for data. SOURCE_STRING is a STRING containing the data to be searched. START_POSITION is an INTEGER which tells Return Value: The index of where MATCH_STRING last occurs (going right to left) in Example:     STRING_INPUT IN$[100];     INTEGER START_LOC;     CHANGE IN$     {       START_LOC =       PRINT("last XYZ occurrence was found at position %d in %s\n", START_LOC, IN$);     } If IN$ was set equal to "Hello, World!" then START_LOC would be 0 since "XYZ" cannot be found. If IN$ was equal to "CPE1704XYZXYZ", then START_LOC would be equal to 11. Version: SIMPL+ Version 2.10.00 or later CUZ 3.137 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > SETSTRING > SetString -------------------------------------------------------------------------------- # SetString Name: SetString Syntax: For X Generation: INTEGER SetString(STRING SOURCE, INTEGER POSITION,                    STRING DESTINATION); For 2-Series:    SIGNED_INTEGER SetString(STRING SOURCE,                  INTEGER POSITION, STRING DESTINATION); Description: Overwrites the bytes in DESTINATION with the bytes in SOURCE starting at POSITION in the DESTINATION string. Performs an overwrite. Parameters: DESTINATION is a STRING containing the string to be modified. POSITION is an INTEGER referencing the starting byte to write at in DESTINATION. 1 is the first byte of the string. SOURCE is a STRING containing the string to use in the operation. Return Value: The new length or an error code, as defined below: For the purposes of the explanation, a string has been declared STRING DESTINATION[MAX_LEN]. The string has a current length defined by LEN(DESTINATION). e.g., If the specified position is beyond the declared length of the destination string: If POSITION \> MAX_LEN, no operation is performed and -8 is returned. e.g., If the entire source string can't be inserted without exceeding the length of the destination string: If POSITION-1+LEN(SOURCE) \> MAX_LEN, the operation is performed, the string is truncated and -4 is returned. e.g., If the position exceeds the current length of the destination: If POSITION \> LEN(DESTINATION), the string is padded with spaces and -2 is returned. e.g., If the source string will make the destination string longer: If POSITION-1+LEN(SOURCE) \> LEN(DESTINATION), the string will be expanded to fit and -1 will be returned. NOTE:  If more than one condition is met (typically -2 and -1 would be met at the same time), the codes are added together as the return value. NOTE:  The subroutine knows the max length of the destination string. If the operation meets none of the above conditions, the new length is returned. The return code may be ignored (as in the example below). Example:     STRING DESTINATION$[100];     DESTINATION$ = "Space XXXX To Fill";     SETSTRING("ABCD", 7, DESTINATION$); Would result in DESTINATION containing the string "Space ABCD To Fill". If the return code were used, it would contain 18 (the string length). Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > String Parsing & Manipulation Functions > UPPER > Upper -------------------------------------------------------------------------------- # Upper Name: Upper Syntax:     STRING Upper(STRING SOURCE); Description: Takes a source string and converts characters with the values a-z (lowercase) to A-Z (uppercase).  You can use the same variable for both the argument and return. e.g., s$=lower(s$); Parameters: SOURCE is a string to be converted to uppercase. SOURCE is not modified, unless it is also used as the return value, e.g., S$=UPPER(S$) Return Value: A STRING containing the uppercase version of SOURCE. Characters that do not fall into the range a-z are not modified and will stay as specified. Example:     STRING_INPUT IN$[100];     STRING UPPER$[100];     CHANGE IN$     {       UPPER$ = UPPER(IN$);       PRINT("Uppercase version of %s is %s\n",IN$, UPPER$);     } In this example, if IN$ contains "Hello There 123!" then UPPER$ contains "HELLO THERE 123!". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > DELAY > Delay -------------------------------------------------------------------------------- # Delay Name: Delay Syntax:     Delay(INTEGER TIME); Description: Forces a task switch and starts a timer for the hundredths of a second specified by TIME. The system continues with the statements after a delay when the delay time has expired. See also: [Wait]. Parameters: TIME is the number of hundredths of a second to delay. For example, 500 specifies a 5-second delay. Return Value: None. Example:     // A delay of 525 hundredths of a second or 5.25 seconds     #define_constant MY_DELAY 525     DELAY(MY_DELAY); Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later [Wait]: ../Wait_Events/WAIT.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > Overview > System Control Overview -------------------------------------------------------------------------------- # System Control Overview These constructs control system behavior and may change the resultant flow of the given SIMPL+ program. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > PROCESSLOGIC > ProcessLogic -------------------------------------------------------------------------------- # ProcessLogic Name: ProcessLogic Syntax:     ProcessLogic(); Description: Forces a task switch away from the current SIMPL+ module, so that the SIMPL program can process the outputs of the SIMPL+ module. Refer to the discussion on [Task Switching]. Parameters: None. Return Value: None. Example:     INTEGER X;     ANALOG_OUTPUT I;     FOR(X=0 TO 25)     {       I = X;       PROCESSLOGIC();     } In this example, the analog output I is updated every pass through the loop. Logic dependent upon the analog value will see the new analog value every pass through the loop. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later [Task Switching]: ../../Task_Switching/Task_Switching_for_2-Series_Control_Systems.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > PULSE > Pulse -------------------------------------------------------------------------------- # Pulse Name: Pulse Syntax:     Pulse(TIME, DIGITAL_OUTPUT OUT); Description: Pulses the output high then low for the specified length of time (in hundredths of a second). When the pulse starts, a task switch is performed so other logic can be processed. Pulse is always high, then low. If the output is already high, the high is ignored, but the low will be sent at the appropriate time. Parameters: TIME is the number of hundredths of a second to pulse. For example, 500 specifies a 5-second delay. OUT is a DIGITAL_OUTPUT that is to be pulsed. Return Value: None. NOTE:  (X-Gen only)   Elements of a DIGITAL_OUTPUT array cannot be used within the Pulse function Example:     // A pulse of 525 hundredths of a second or 5.25 seconds     #define_constant MY_PULSE_TIME 525     DIGITAL_OUTPUT OutputToPulse;     PULSE(MY_PULSE_TIME, OutputToPulse); This will execute immediately and output a pulse of 5.25 seconds to the digital output OutputToPulse. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > TERMINATEEVENT > TerminateEvent -------------------------------------------------------------------------------- # TerminateEvent Name: TerminateEvent Syntax:     TerminateEvent; Description: Exits a CHANGE, PUSH, or RELEASE event. It may also be used to exit a loop in the main() function if desired. TERMINATEEVENT cannot be used inside of a function. Example:     INTEGER X;     ANALOG_INPUT Y;     CHANGE Y     {       X=0;       WHILE(X\<25)       {         IF(Y = 69)           TerminateEvent;         X = X + 1;         PRINT("X=%d\n", X);       }     } In this example, the CHANGE event will terminate if the ANALOG_INPUT Y equals the value of 69. Otherwise, the CHANGE will exit after the WHILE loop finishes. Version: X Generation SIMPL v1.20.01 and later 2-Series SIMPL v2.01.05 and later.  Within functions, returns from the function, it does NOT terminate the event.   Existing code that relies on the event terminating should be revised. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Control > WaitForInitializationComplete -------------------------------------------------------------------------------- # WaitForInitializationComplete Name: WaitForInitializationComplete Syntax: SIGNED_INTEGER WaitForInitializationComplete() Description: Waits for the logic processor to perform its first logic solution before returning control back to the calling task.  This makes it possible to access inputs and outputs in function main() that are modified during the initial logic solution (propagating signals with logic "1" attached).  The function Main() starts to run at when the Simpl+ module is initialized.  This allows any initial values for global variables to be set before any event handlers are run.  However, since it does run at initialization time, any inputs or outputs accessed would have their initial value of 0 when accessed.  WaitForInitializationComplete will stop main() from running until the "Initialization Complete" message appears in Toolbox.  This means that any input or output whose value is modified while processing the "1" logic solution, will now have the correct values. Parameters: None. Return Value: Returns 0 if successful , \<0 if an error occurs. Example: DIGITAL_INPUT   diEnable; INTEGER giProcessEnabled; main() {         // initialize local variables.         giProcessEnabled = 0;         if ( WaitForInitializationComplete() \< 0 )         {             print(Error waiting for initialization complete\n");             return;         }         // now we can access variables that were processed with the logic "1" solution         while (diEnable)         {             giProcessEnabled = 1;             // rest of the code for the process.         } } Version:         X Generation:  Not Supported 2-Series:  SIMPL v2.05.17 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GenerateUserError -------------------------------------------------------------------------------- # GenerateUserError Name: GenerateUserError Syntax: GenerateUserError(\ [, \ ...]); Description: Places an error message into the control system's error log. Parameters: \ is a quoted string that contains text and formatting information. Format specifiers are of the form: %[[Pad]Width]specifier See Print for a list and description of valid Format Specifiers. Return Value: None. Example:    Function MyFunc()    { STRING sError; sError = "Projector"; GenerateUserError( "The %s bulb has exceeded %d hours", sError, 1000 );    } Version: X Generation:  Not Supported 2-Series:  SIMPL v2.04.11 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GenerateUserNotice -------------------------------------------------------------------------------- # GenerateUserNotice Name: GenerateUserNotice Syntax: GenerateUserNotice(\ [, \ ...]); Description: Places a notification message into the control system's error log Parameters: \ is a quoted string that contains text and formatting information. Format specifiers are of the form: %[[Pad]Width]specifier See Print for a list and description of valid Format Specifiers. Return Value: None. Example: Function MyFunc() { STRING sNotice; sNotice = "Projector"; GenerateUserNotice( "The %s bulb has a total of %d hours", sNotice, 500 ); } Version: X Generation:  Not Supported 2-Series:  SIMPL v2.04.11 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GenerateUserWarning -------------------------------------------------------------------------------- # GenerateUserWarning Name: GenerateUserWarning Syntax: GenerateUserWarning(\ [, \ ...]); Description: Places a warning message into the control system's error log. Parameters: \ is a quoted string that contains text and formatting information. Format specifiers are of the form: %[[Pad]Width]specifier See Print for a list and description of valid Format Specifiers. Return Value: None. Example:    Function MyFunc()    { STRING sWarning; sWarning = "Projector"; GenerateUserWarning( "The %s bulb has a total of %d hours", sWarning, 800 );    } Version: X Generation:  Not Supported 2-Series:  SIMPL v2.04.11 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetCIPDev > GetCIP -------------------------------------------------------------------------------- # GetCIP Name: GetCIP Syntax:     INTEGER GetCIP(INTEGER CIPID, INTEGER JOIN_NUMBER,                    INTEGER TYPE); Description: Retrieves the current state of the join number on a particular CIP ID (referred to as IP ID in SIMPL+). Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. NOTE:  CIP is defined as Cresnet (over) Internet Protocol. Parameters: CIPID is an INTEGER containing the ID of the CIP device to query. JOIN_NUMBER is an INTEGER containing the Join number to get the status. For touchpanels, the join number is identical to the press/feedback number. For other devices, contact Crestron customer service. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) NOTE:  Access to serial signals is not supported. Return Value: An Integer. For Digital values, a non-zero value indicates a logic high and a 0 value indicates a logic low. For analog values, a 16-bit number is returned corresponding to the state of the analog join. Example: Assuming a relay card has been defined in Slot 1 and Relay A2 has a signal name tied to it, and a CEN-IO has been defined at CIP ID 03 and cue i1 has a signal tied to it, this SIMPL+ statement will connect the two:     SetSlot(1,2,dout) = GetCIP(0x03,18,din); NOTE:  In the above example statement, the join number representing cue i1 on the CEN-IO is 18. NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetCresnetDev > GetCresnet -------------------------------------------------------------------------------- # GetCresnet Name: GetCresnet Syntax:     INTEGER GetCresnet(INTEGER CRESNET_ID, INTEGER JOIN_NUMBER,                        INTEGER TYPE); Description: Retrieves the current state of the join number on a particular Cresnet Network ID. Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. Parameters: CRESNET_ID is an INTEGER containing the ID of the Cresnet Network device to query. JOIN_NUMBER is an INTEGER containing the Join number to get the status. For touchpanels, the join number is identical to the press/feedback number. For other devices, contact Crestron customer service. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) NOTE:  Access to serial signals is not supported. Return Value: An Integer. For Digital values, a non-zero value indicates a logic high and a 0 value indicates a logic low. For analog values, a 16-bit number is returned corresponding to the state of the analog join. Example: Assuming a relay card has been defined in Slot 1 and Relay A2 has a signal name tied to it, and a touch screen has been defined at Cresnet ID 07, and press 42 has a signal name tied to it, this SIMPL+ statement will connect the two:     SetSlot(1,2,dout) = GetCresnet(0x07,42,din); NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetModelNumber -------------------------------------------------------------------------------- # GetModelNumber Name: GetModelNumber  Syntax:     GetModelNumber Description: Returns the product name. Example: FUNCTION DisplayProduct() {      PRINT( “This is a %s”, GetModelNumber() ); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetProgramNumber -------------------------------------------------------------------------------- # GetProgramNumber Name: GetProgramNumber  Syntax:     GetProgramNumber Description: Returns which program the module is executing from. Example: FUNCTION DisplayProgramNumber() {      PRINT( “This is the %d”, GetProgramNumber() ); } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetSeries -------------------------------------------------------------------------------- # GetSeries Name: GetSeries  Syntax:     GetSeries Description: Returns the product series.  For example, the 3-series architecture will return 3 and the 2-series architecture will return 2. Example: FUNCTION GetMySeries() {      SWITCH( GetSeries() )      {           CASE (2):                PRINT( “2-Series” );           CASE (3):                PRINT( “3-series” );      } } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetSlotDev > GetSlot -------------------------------------------------------------------------------- # GetSlot Name: GetSlot Syntax:     INTEGER GetSlot(INTEGER SLOT_NUMBER, INTEGER JOIN_NUMBER,                     INTEGER TYPE); Description: Retrieves the current state of the join number on a particular card. Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. Parameters: SLOT_NUMBER is an INTEGER containing the slot number of the card to query. JOIN_NUMBER is an INTEGER containing the Join number to get the status. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) NOTE:  Access to serial signals is not supported. Return Value: An Integer. For Digital values, a non-zero value indicates a logic high and a 0 value indicates a logic low. For analog values, a 16-bit number is returned corresponding to the state of the analog join. Example: Assuming a relay card has been defined in Slot 1 and Relay A2 has a signal name tied to it, and a CNXIO-16 has been defined in Slot 2 and cue i1 has a signal tied to it, this SIMPL+ statement will connect the two:     SetSlot(1,2,dout) = GetSlot(2,1,din); NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetSymbolInstanceName -------------------------------------------------------------------------------- # GetSymbolInstanceName Name: GetSymbolInstanceName Syntax:     STRING GetSymbolInstanceName(); Description: Returns the symbol "S-" and the number where this SIMPL+ symbol is located within the SIMPL program. Parameters: None. Return Value: A string indicating the location of the SIMPL+ symbol in SIMPL. For example, if the SIMPL+ symbol is at S-5.2 in the SIMPL program, the returned string will be "S-5.2".  If that same symbol resides in a macro that is located at S-6 in the SIMPL program, the returned string will be "S-6:S-5.2" Example: STRING InstanceName[20]; InstanceName=GetSymbolInstanceName(); Print("Instance Name is: %s", InstanceName); Assuming the SIMPL+ symbol is located at S-5.2 in the SIMPL Program, the Instance Name is: S-5.2 Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > GetSymbolReferenceName -------------------------------------------------------------------------------- # GetSymbolReferenceName Name: GetSymbolReferenceName Syntax:     STRING GetSymbolReferenceName(); Description: Returns the string entered into the [Reference Name] SIMPL+ symbol in SIMPL corresponding to the SIMPL+ module. NOTE:  CIP is defined as Cresnet (over) Internet Protocol. Parameters: None. Return Value: Returns the string entered into the Reference Name field of a SIMPL+ symbol in SIMPL. If no Reference Name has been entered, an empty string is returned. Example: STRING RefName[20]; Function Main() { WaitForInitializationComplete(); RefName=GetSymbolReferenceName(); Print("Reference Name is: %s.\n", RefName); } Assuming the Reference Name Parameter is, for example, Kitchen Light Control, "Reference Name is: Kitchen Light Control" is the returned string. Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > IsSignalDefined -------------------------------------------------------------------------------- # IsSignalDefined Name: IsSignalDefined Syntax:     INTEGER IsSignalDefined \; Description: Retrieves the current SIMPL signal number associated with a particular input or output. This is generally used to determine if a particular input or output on a gate is being used, and generally used with arrayed inputs or outputs. This can be used to build a gate of a predetermined maximum size, and allow the user to add and subtract signals on the input or output of the gate (i.e., the program would be written to iterate through a DIGITAL_INPUT array until IsSignalDefined returns a 0). Parameters: Legal output and input signal types are ANALOG_INPUT, ANALOG_OUTPUT, BUFFER_INPUT, DIGITAL_INPUT, DIGITAL_OUTPUT, STRING_INPUT, STRING_OUTPUT. Return Value: The particular input or output is tied to an integer giving the signal number. If a signal has been tied to that input or output of the gate, a non-zero value will be returned. If the input/output  is tied to 0 in the SIMPL program or is not defined, then 0 will be returned. If a digital input/output in the SIMPL program is tied to 1, then 1 is returned.  If an analog or serial input/output in the SIMPL program is tied to 1, then 0 is returned. Example:     DIGITAL_INPUT INS[20];     INTEGER NumInputs;     FUNCTION MAIN()     {        FOR(NumInputs = 20 to 1 Step -1)        IF(IsSignalDefined(INS[NumInputs]))           Break;     } This example computes how many inputs are used on the gate. It should be noted that it is useful to count backwards from the end of the gate. If the user tied five signals, a 0, and then five more signals, this would yield the correct result that the 11th input was the last one used. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > MakeProgramFilename -------------------------------------------------------------------------------- # MakeProgramFilename Name: MakeProgramFilename Syntax:     MakeProgramFilename Description: Takes in the filename (which would be the program path or anything that the user wants) and prepends  that with the Program ID Tag. The Program ID Tag is specified in the Header of the SIMPL program. For example: if running in program and the user passes in  "\Simpl\App01\MyProgram" as the filename and the Program ID Tag is set to "HVAC" then this function would return "\Simpl\App01\HVAC_MyProgram". NOTE:  In the 2 Series, Program ID Tags are not used, so the same name is returned. Example: FUNCTION MyFunc() {      // SIMPL Program ID Tag is set to "HVAC      PRINT( “ProgramFileName = %s”, MakeProgramFilename("\\Simpl\\App01\\MyProgram") );      // prints: "\Simpl\App01\HVAC_MyProgram" } Version: X Generation:  Not Supported 2-Series:  Not Supported 3-Series: v \<\> and above -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > Overview > System Interfacing Overview -------------------------------------------------------------------------------- # System Interfacing Overview These functions control the way the SIMPL+ program communicates with Cresnet network devices and the CPU. | | | |----|----| | Function | Description | | [GetCIP] | Retrieves the current state of the join number on a particular CIP ID. | | [GetCresnet] | Retrieves the current state of the join number on a particular Cresnet Network ID. | | [GetModelNumber] | Returns the product name. | | [GetSeries] | Returns the product series.  For example, the 3-series architecture will return 3 and the 2-series architecture will return 2. | | [GetSlot] | Retrieves the current state of the join number on a particular card. | | [GetSymbolInstanceName] | Returns the symbol "S-" and the number where this SIMPL+ symbol is located within the SIMPL program. | | [GetSymbolReferenceName] | Returns the string entered into the [Reference Name] SIMPL+ symbol in SIMPL corresponding to the SIMPL+ module. | | [IsSignalDefined] | Retrieves the current SIMPL signal number associated with a particular input or output. | | [MakeProgramFilename] | Takes in the filename (which would be the program path or anything that the user wants) and prepends  that with the Program ID Tag. The Program ID Tag is specified in the Header of the SIMPL program. | | [SendCresnetPacket] | Sends the string specified by PACKET onto the Cresnet network. | | [SendPacketToCPU] | Sends the string specified by PACKET to the Cresnet CPU. | | [SetCIP] | Sets the state of the join number on a particular CIP ID. | | [SetCresnet] | Sets the state of the join number on a particular Cresnet Network ID. | | [SetSlot] | Sets the state of the join number on a particular card slot. | [GetCIP]: GetCIPDev.md [GetCresnet]: GetCresnetDev.md [GetModelNumber]: GetModelNumber.md [GetSeries]: GetSeries.md [GetSlot]: GetSlotDev.md [GetSymbolInstanceName]: GetSymbolInstanceName.md [GetSymbolReferenceName]: GetSymbolReferenceName.md [IsSignalDefined]: IsSignalDefined.md [MakeProgramFilename]: MakeProgramFilename.md [SendCresnetPacket]: SendCresnetPacket.md [SendPacketToCPU]: SendPacketToCPU.md [SetCIP]: SetCIPDev.md [SetCresnet]: SetCresnetDev.md [SetSlot]: SetSlotDev.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > SendCresnetPacket -------------------------------------------------------------------------------- # SendCresnetPacket Name: SendCresnetPacket Syntax:     SendCresnetPacket(STRING PACKET); Description: Sends the string specified by PACKET onto the Cresnet network. It duplicates the function of the SIMPL symbol "Network Transmission (Speedkey:  NTX)." This function is not used in general programming. Parameters: PACKET is a string containing the command to put on the Cresnet network. Return Value: None. Example:     SendCresnetPacket("\xFF\x03\x02"); This example will send a broadcast message to all touchpanels causing them to enter sleep mode. The preferable way to do this is use the SLEEP input of the BROADCAST symbol in SIMPL. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > SendPacketToCPU -------------------------------------------------------------------------------- # SendPacketToCPU Name: SendPacketToCPU Syntax:     SendPacketToCPU(STRING PACKET); Description: Sends the string specified by PACKET to the Cresnet CPU. This is normally used for sending ESC style commands to the CPU for control. This function duplicates the functionality of the SIMPL symbol "Send Message to CPU (Speedkey:  TMSG)." This function is not used in general programming. Parameters: PACKET is a string containing the command to send to the CPU. Return Value: None. Example:     SendPacketToCPU("\x1BDFF\r"); This example will turn the Super Debugger on, which shows all network transitions on the console port of the control system. This command would normally be typed in manually through the Crestron Viewport, since it is for debugging only. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > SetCIPDev > SetCIP -------------------------------------------------------------------------------- # SetCIP Name: SetCIP Syntax:     SetCIP(INTEGER CIPID, INTEGER JOIN_NUMBER,            INTEGER TYPE); Description: Sets the state of the join number on a particular CIP ID. Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. Parameters: CIPID is an INTEGER containing the ID of the CIP device to set the join number. JOIN_NUMBER is an INTEGER containing the Join number to set. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) Return Value: None. Example: Assuming a CEN-IO has been defined at CIP ID 03 and Relay1 has a signal named tied to it, and a touch screen has been defined at Cresnet ID 07, and press 42 has a signal name tied to it, this SIMPL+ statement will connect the two:     SetCIP(0x03,1,dout) = GetCresnet(0x07,42,din); NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > SetCresnetDev > SetCresnet -------------------------------------------------------------------------------- # SetCresnet Name: SetCresnet Syntax:     SetCresnet(INTEGER CRESNET_ID, INTEGER JOIN_NUMBER,                INTEGER TYPE); Description: Sets the state of the join number on a particular Cresnet Network ID. Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. Parameters: CRESNET_ID is an INTEGER containing the ID of the Cresnet Network device to set the join number. JOIN_NUMBER is an INTEGER containing the Join number to set. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) Return Value: None. Example: Assuming a touch screen has been defined at Cresnet ID 07, and press 42 and feedback 69 have signal names tied to them, this SIMPL+ statement will connect the two:     SetCresnet(0x07,69,dout) = GetCresnet(0x07,42,din); NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > System Interfacing > SetSlotDev > SetSlot -------------------------------------------------------------------------------- # SetSlot Name: SetSlot Syntax:     SetSlot(INTEGER SLOT_NUMBER, INTEGER JOIN_NUMBER,             INTEGER TYPE); Description: Sets the state of the join number on a particular card slot. Note that the device must be defined in SIMPL and the join number to use must have a signal tied to it for this function to work. Parameters: SLOT_NUMBER is an INTEGER containing the slot number of card to set the join number. JOIN_NUMBER is an INTEGER containing the Join number to set. TYPE is one of several predefined constants: din:        Digital inputs from device (symbol output list) ain:        Analog inputs from device (symbol output list) dout:      Digital outputs to device (symbol input list) aout:      Analog outputs to device (symbol input list) Return Value: None. Example: Assuming a relay card has been defined in Slot 1 and Relay A2 has a signal name tied to it, and a touch screen has been defined at Cresnet ID 07, and press 42 has a signal name tied to it, this SIMPL+ statement will connect the two:     SetSlot(1,2,dout) = GetCresnet(0x07,42,din); NOTE:  This is not a permanent connection; it will only set the state when this statement is executed. Version: X Generation:  SIMPL v1.50.06 and later 2-Series:  Not Supported. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > Clock Driver -------------------------------------------------------------------------------- # Clock Driver The Clock Driver symbol makes the internal clock of the control system available to other symbols. In addition, its presence alone will synchronize the internal clocks on touchpanels with the internal clock of the control system. (The output signal and parameter need not be defined.) The \ parameter specifies the format for Daylight Savings Time, as shown in the following table: | | | |----|----| | \ | Format | | 0 | No DST | | 1 | U.S. (first Sunday in April to the last Sunday in October) | | 2 | Southern Hemisphere (first Sunday in October to the 3rd Sunday in March) | | 3 |  Same as 2 (for compatibility with MSX) | | 4 (2-Series only) | European Union Standard (last Sunday in March to the last Sunday in October) | | 5 (2-Series only) |  Egypt (last Friday in April to the last Thursday in September) | Entering Daylight Savings Time drives the time back one hour beginning at 2:00 A.M. Leaving Daylight Savings Time moves the time ahead one hour beginning at 2:00 A.M. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > DATE > Date -------------------------------------------------------------------------------- # Date Name: Date Syntax:     STRING Date(INTEGER FORMAT); Description: Returns a string corresponding to the current date with the specified FORMAT. Parameters: FORMAT is an integer describing the way to format the date for the return. Valid formats are 1 through 4. FORMAT 1 returns a string in the form MM/DD/YYYY FORMAT 2 returns a string in the form DD/MM/YYYY FORMAT 3 returns a string in the form YYYY/MM/DD FORMAT 4 returns a string in the form MM/DD/YY In format 4, the year 2000 is shown as 00. Digits 58 - 99 are treated as 1958-1999 and 00-57 are treated as 2000 through 2057. Return Value: A STRING corresponding to the current date. Example:     STRING TheDate$[100];     FUNCTION MAIN()     {       TheDate$=DATE(1);       PRINT("The date is %s\n", TheDate$);     } This would print a string such as "The date is 03/25/1999". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > DAY > Day -------------------------------------------------------------------------------- # Day Name: Day Syntax:     STRING Day(); Description: Returns the day of the week as a STRING. Parameters: None. Return Value: The day of the week is returned in a string. Valid returns are Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, or Saturday. Example:     STRING TheDay$[100];     FUNCTION MAIN()     {       TheDay$=DAY();       PRINT("The day of the week is %s\n", TheDay$);     } An example output of this would be "The day of the week is Monday". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEDATE > FileDate -------------------------------------------------------------------------------- # FileDate Name: FileDate Syntax:     STRING FileDate(FILE_INFO Info, INTEGER FORMAT); Description: Returns a string corresponding to the current date of the specified file with the specified FORMAT. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description) FORMAT is an integer describing the way to format the date for the return. Valid formats are 1 through 4. FORMAT 1 returns a string in the form MM/DD/YYYY FORMAT 2 returns a string in the form DD/MM/YYYY FORMAT 3 returns a string in the form YYYY/MM/DD FORMAT 4 returns a string in the form MM/DD/YY In format 4, the year 2000 is shown as 00. Digits 58 - 99 are treated as 1958-1999 and 00-57 are treated as 2000 through 2057. Return Value: A STRING corresponding to the current date. Example:   (see [File Functions Overview])     STRING TheDate$[100];     FILE_INFO FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       TheDate$ = FileDate(FileInfo, 1);       PRINT ( "Date of file = %s\n", TheDate$ );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); This would print a string such as "Date of file =  03/25/2003". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEDAY > FileDay -------------------------------------------------------------------------------- # FileDay Name: FileDay Syntax:     STRING FileDay(FILE_INFO Info); Description: Returns the day of the week of the file as a STRING. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The day of the week of the file is returned in a string. Valid returns are Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, or Saturday. Example:   (see [File Functions Overview])     STRING TheDay$[100];     FILE_INFO FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       TheDay$ = FileDay(FileInfo);       PRINT ( "Day of file = %s\n", TheDay$ );       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Day of file = Monday". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETDATENUM > FileGetDateNum -------------------------------------------------------------------------------- # FileGetDateNum Name: FileGetDateNum Syntax:     SIGNED_INTEGER FileGetDateNum(FILEINFO Info); Description: Returns an integer corresponding to the day of the month of the file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The day of the month as an integer from 1 to 31. Example:   (see [File Functions Overview])     INTEGER NumDateOfMonth;     [FILE_INFO] FileInfo;     INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumDateOfMonth = FileGetDateNum(FileInfo);       PRINT ( "Day of the month of file = %d\n", NumDateOfMonth);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Day of the month of file = 25". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETDAYOFWEEKNUM > FileGetDayOfWeekNum -------------------------------------------------------------------------------- # FileGetDayOfWeekNum Name: FileGetDayOfWeekNum Syntax:     SIGNED_INTEGER FileGetDayOfWeekNum(FILEINFO Info); Description: Returns an integer corresponding to the day of the week of file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The day of the week as an integer from 0 to 6; 0 represents Sunday to 6 representing Saturday. Example:   (see [File Functions Overview])    INTEGER NumDayOfWeek;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumDayOfWeek = FileGetDayOfWeekNum(FileInfo);       PRINT ( "Day of week of file = %d\n", NumDayOfWeek);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )       PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Day of week of file = 4". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETHOURNUM > FileGetHourNum -------------------------------------------------------------------------------- # FileGetHourNum Name: FileGetHourNum Syntax:     SIGNED_INTEGER FileGetHourNum(FILEINFO Info); Description: Returns an integer corresponding to the number of hours in the time of the file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The number of hours from 0 to 23 (24-hour time format). Example:   (see [File Functions Overview])     INTEGER NumHours;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumHours = FileGetHourNum(FileInfo);       PRINT ( "Hours of file time = %d\n", NumHours);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Hours of file time = 22". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETMINUTESNUM > FileGetMinutesNum -------------------------------------------------------------------------------- # FileGetMinutesNum Name: 2-series only Syntax:     SIGNED_INTEGER FileGetMinutesNum(FILEINFO Info); Description: Returns an integer corresponding to the number of minutes in the file time. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The number of minutes from 0 to 59. Example:   (see [File Functions Overview])    INTEGER NumMinutes;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumMinutes = FileGetMinutesNum(FileInfo);       PRINT ( "Minutes of file time = %d\n", NumMinutes);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Minutes of file time = 33". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETMONTHNUM > FileGetMonthNum -------------------------------------------------------------------------------- # FileGetMonthNum Name: FileGetMonthNum Syntax:     SIGNED_INTEGER FileGetMonthNum(FILEINFO Info); Description: Returns an integer corresponding to the month of the year of file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] ). Return Value: The month of the year as an integer from 1 to 12. Example:   (see [File Functions Overview])     INTEGER NumMonth;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumMonth = FileGetMonthNum(FileInfo);       PRINT ( "Month of file date = %d\n", NumMonth);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Month of file date = 9". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETSECONDSNUM > FileGetSecondsNum -------------------------------------------------------------------------------- # FileGetSecondsNum Name: FileGetSecondsNum Syntax:     SIGNED_INTEGER FileGetSecondsNum(FILEINFO Info); Description: Returns an integer corresponding to the number of seconds in the time of the file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The number of seconds from 0 to 59. Example:   (see [File Functions Overview])    INTEGER NumSeconds;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumSeconds = FileGetSecondsNum(FileInfo);       PRINT ( "Seconds of file time = %d\n", NumSeconds);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Seconds of file time = 25". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEGETYEARNUM > FileGetYearNum -------------------------------------------------------------------------------- # FileGetYearNum Name: FileGetYearNum Syntax:     SIGNED_INTEGER FileGetYearNum(FILEINFO Info); Description: Returns an integer corresponding to the year of the file. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The year as an integer. The full year is specified. For example, the year 2003 will return the integer 2003. Example:   (see [File Functions Overview])    INTEGER NumYear;     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       NumYear = FileGetYearNum(FileInfo);       PRINT ( "Year of file date = %d\n", NumYear);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output from this would be "Year of file date = 1999". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILEMONTH > FileMonth -------------------------------------------------------------------------------- # FileMonth Name: FileMonth Syntax:     STRING FileMonth(FILEINFO Info); Description: Returns the month of the file date as a string. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The current month is returned in a string. Valid returns are January, February, March, April, May, June, July, August, September, October, November, or December. Example:   (see [File Functions Overview])     STRING TheMonth$[100];     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       TheMonth$ = FileMONTH(FileInfo);       PRINT ( "Month of file date = %s\n", TheMonth$);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output of this would be "Month of file date = September". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > FILETIME > FileTime -------------------------------------------------------------------------------- # FileTime Name: FileTime Syntax:     STRING FileTime(FILEINFO Info); Description: Returns a string containing the current system time. Parameters: INFO – structure containing the information about a found file (see [FindFirst] for description). Return Value: The return string contains the time in HH:MM:SS format, in 24-hour time. If a value is not two digits wide, it is padded with leading 0s. Example:   (see [File Functions Overview])    STRING TheTime$[100];     [FILE_INFO] FileInfo;     SIGNED_INTEGER Found; StartFileOperations();     Found = FindFirst("\*.dat", FileInfo );     WHILE (Found = 0)     {       TheTime$=TIME();       PRINT ( "File time = %s\n", TheTime$);       Found = FindNext(FileInfo);     }     IF ( FindClose() \< 0 )        PRINT ( "Error in closing find operation\n" ); EndFileOperations(); An example output from this would be "File time = 14:25:32". Version: X Generation:  Not Supported 2-Series:  SIMPL Version 2.02.10 and later      [FindFirst]: ../File_Functions/File_First.md [File Functions Overview]: ../File_Functions/File_Functions_Overview.md [FILE_INFO]: ../File_Functions/File_INFO_Structure.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETDATENUM -------------------------------------------------------------------------------- # GETDATENUM Name: GetDateNum Syntax:     INTEGER GetDateNum(); Description: Returns an integer corresponding to the current day of the month. Parameters: None. Return Value: The day of the month as an integer from 1 to 31. Example:     INTEGER NumDateOfMonth;     FUNCTION MAIN()     {       NumDateOfMonth = GetDateNum();       PRINT("The current day of the month is %d\n", NumDateOfMonth);     } An example output of this would be "The current day of the month is 25". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETDAYOFWEEKNUM -------------------------------------------------------------------------------- # GETDAYOFWEEKNUM Name: GetDayOfWeekNum Syntax:     INTEGER GetDayOfWeekNum(); Description: Returns an integer corresponding to the current day of the week. Parameters: None. Return Value: The day of the week as an integer from 0 to 6; 0 represents Sunday to 6 representing Saturday. Example:     INTEGER NumDayOfWeek;     FUNCTION MAIN()     {       NumDayOfWeek = GetDayOfWeekNum();       PRINT("The current day of the week is %d\n", NumDayOfWeek);     } An example output of this would be "The current day of the week is 4". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETDST > GetDst -------------------------------------------------------------------------------- # GetDst Name: GetDst Syntax:     INTEGER GetDst() Description: Gets the current DST (Daylight Savings Time) state. In order to set the DST state, a [Clock Driver] symbol with a DST value is needed in the SIMPL Program. Parameters: None Return Value: An INTEGER containing the DST status: 0: Unknown 1: In DST 2: Not in DST Example:     INTEGER DstMode;     DstMode = GetDst();     If(DstMode = 0)        Print("DST Mode is currently unknown.\n");     Else if (DstMode = 1)        Print("DST Mode is currently On (In DST).\n");     Else if (DstMode = 2)        Print("DST Mode is currently Off (Not in DST).\n"); This example will return one of the following strings based on the DST status: DST Mode is currently Unknown. DST Mode is currently On (In DST). DST Mode is currently Off (Not in DST). Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later required [Clock Driver]: javascript:void(0); -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETGMTOFFSET > GetGmtOffset -------------------------------------------------------------------------------- # GetGmtOffset Name: GetGmtOffset Syntax:     SIGNED_INTEGER GetGmtOffset(); Description: Retrieves the GMT Offset that was configured via the consol command GMTOFFSET or through the SetGmtOffset() function. Parameters: None. Return Value: A SIGNED_INTEGER containing the offset in minutes. Example:     SIGNED_INTEGER SystemGmtOffset;     SystemGmtOffset = GetGmtOffset();     Print("GmtOffset = %d minutes\n", SystemGmtOffset); In this example the GmtOffset would be the value of %d expressed as a positive or negative number. Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETHOURNUM -------------------------------------------------------------------------------- # GETHOURNUM Name: GetHourNum Syntax:     INTEGER GetHourNum(); Description: Returns an integer corresponding to the number of hours in the current time. Parameters: None. Return Value: The number of hours from 0 to 23 (24-hour time format). Example:     INTEGER NumHours;     FUNCTION MAIN()     {       NumHours = GetHourNum();       PRINT("The Number of hours on the clock is %d\n", NumHours);     } An example output of this would be "The Number of hours on the clock is 22". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETHSECONDS -------------------------------------------------------------------------------- # GETHSECONDS Name: GetHSeconds Syntax:     INTEGER GetHSeconds(); Description: Returns an integer corresponding to the number of hundredths of a second based on the system clock. Typically, this function could be used for very fine timing, to determine if a specific amount of time has elapsed. Parameters: None. Return Value: The number of hundredths of a second based on the system clock. Example:     INTEGER OldTime, NewTime, Loop;     Loop=0;     OldTime=GETHSECONDS();     WHILE(Loop \< 10000)     {       Loop = Loop + 1     }     NewTime=GETHSECONDS();     PRINT ("Elapsed Time is %d hundredths of a second.\n",            Newtime-OldTime); The output of this code would be "Elapsed Time is 400 hundredths of a second." NOTE: This is bad programming as it ties up the CPU. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETMINUTESNUM -------------------------------------------------------------------------------- # GETMINUTESNUM Name: GetMinutesNum Syntax:     INTEGER GetMinutesNum(); Description: Returns an integer corresponding to the number of minutes in the current time. Parameters: None. Return Value: The number of minutes from 0 to 59. Example:     INTEGER NumMinutes;     FUNCTION MAIN()     {       NumMinutes = GetMinutesNum();       PRINT("The Number of minutes on the clock is %d\n", NumMinutes);     } An example output of this would be "The Number of minutes on the clock is 33". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETMONTHNUM -------------------------------------------------------------------------------- # GETMONTHNUM Name: GetMonthNum Syntax:     INTEGER GetMonthNum(); Description: Returns an integer corresponding to the current month of the year. Parameters: None. Return Value: The month of the year as an integer from 1 to 12. Example:     INTEGER NumMonth;     FUNCTION MAIN()     {       NumMonth = GetMonthNum();       PRINT("The current month of the year is %d\n", NumMonth);     } An example output of this would be "The current month of the year is 9". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETSECONDSNUM -------------------------------------------------------------------------------- # GETSECONDSNUM Name: GetSecondsNum Syntax:     INTEGER GetSecondsNum(); Description: Returns an integer corresponding to the number of seconds in the current time. Parameters: None. Return Value: The number of seconds from 0 to 59. Example:     INTEGER NumSeconds;     FUNCTION MAIN()     {       NumSeconds = GetSecondsNum();       PRINT("The Number of seconds on the clock is %d\n", NumSeconds);     } An example output of this would be "The Number of seconds on the clock is 25". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETTICKS -------------------------------------------------------------------------------- # GETTICKS Name: GetTicks Syntax:     INTEGER GetTicks(); Description: Returns an integer corresponding to the number of system ticks. Each tick is 1/112.5 seconds for X-Generation and 0.01 seconds for 2-Series, same as GetHSeconds(). Typically, this function could be used for very fine timing, to determine if a specific amount of time has elapsed. Use of this function is discouraged, use GetHSeconds() instead. Parameters: None. Return Value: The number of ticks in the clock. Example:     INTEGER OldTime, NewTime, Loop;     Loop=0;     OldTime=GETTICKS();     WHILE(Loop \< 10000)     {       Loop = Loop + 1;     }     NewTime=GETTICKS();     PRINT("Elapsed Time is %d ticks\n", Newtime-OldTime); An example output from this code fragment would be "Elapsed Time is 7000 ticks". NOTE: This is bad programming as it ties up the CPU. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > GETYEARNUM -------------------------------------------------------------------------------- # GETYEARNUM Name: GetYearNum Syntax:     INTEGER GetYearNum(); Description: Returns an integer corresponding to the current year. Parameters: None. Return Value: The year as an integer. The full year is specified. For example, the year 2000 will return the integer 2000. Example:     INTEGER NumYear;     FUNCTION MAIN()     {       NumYear = GetYearNum();       PRINT("The current year is %d\n", NumYear);     } An example output from this would be "The current year is 1999". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > MONTH -------------------------------------------------------------------------------- # MONTH Name: Month Syntax:     STRING Month(); Description: Returns the current month as a string. Parameters: None. Return Value: The current month is returned in a string. Valid returns are January, February, March, April, May, June, July, August, September, October, November, or December. Example:     STRING TheMonth$[100];     FUNCTION MAIN()     {       TheMonth$=MONTH();       PRINT("The Month is %s\n", TheMonth$);     } An example output of this would be "The Month is September". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > Overview > Time and Date Functions Overview -------------------------------------------------------------------------------- # Time and Date Functions Overview Time and Date functions in a given SIMPL+ program are used to retrieve information about the current date and time from the system clock. Values can be retrieved as either text strings i.e. "January" or as integer values. Typically, integer values are used if computations need to be performed (i.e. when the date is the 25th, perform a specific action). | | | |----|----| | Function | Description | | [Date] | Returns a string corresponding to the current date with the specified FORMAT. | | [Day] | Returns the day of the week as a STRING. | | [FileDate] | Returns a string corresponding to the current date of the specified file with the specified FORMAT. | | [FileDay] | Returns the day of the week of the file as a STRING. | | [FileGetDateNum] | Returns an integer corresponding to the day of the month of the file. | | [FileGetDayOfWeekNum] | Returns an integer corresponding to the day of the week of file. | | [FileGetHourNum] | Returns an integer corresponding to the number of hours in the time of the file. | | [FileGetMinutesNum] | Returns an integer corresponding to the number of minutes in the file time. | | [FileGetMonthNum] | Returns an integer corresponding to the month of the year of file. | | [FileGetSecondsNum] | Returns an integer corresponding to the number of seconds in the time of the file. | | [FileGetYearNum] | Returns an integer corresponding to the year of the file. | | [FileMonth] | Returns a string containing the current system time. | | [FileTime] | Returns a string containing the current system time. | | [GetDateNum] | Returns an integer corresponding to the current day of the month. | | [GetDayOfWeekNum] | Returns an integer corresponding to the current day of the week. | | [GetDst] | Gets the current DST (Daylight Savings Time) state. | | [GetGmtOffset] | Retrieves the GMT Offset that was configured via the consol command GMTOFFSET or through the SetGmtOffset() function. | | [GetHourNum] | Returns an integer corresponding to the number of hours in the current time. | | [GetHSeconds] | Returns an integer corresponding to the number of hundredths of a second based on the system clock. | | [GetMinutesNum] | Returns an integer corresponding to the number of minutes in the current time. | | [GetMonthNum] | Returns an integer corresponding to the current month of the year. | | [GetSecondsNum] | Returns an integer corresponding to the number of seconds in the current time. | | [GetTicks] | Returns an integer corresponding to the number of system ticks. | | [GetYearNum] | Returns an integer corresponding to the current year. | | [Month] | Returns the current month as a string. | | [SetClock] | Sets the system clock. | | [SetDate] | Sets the system date. | | [SetGmtOffset] | Sets the system GMT Offset. | | [Time] | Returns a string containing the current system time. | [Date]: DATE.md [Day]: DAY.md [FileDate]: FILEDATE.md [FileDay]: FILEDAY.md [FileGetDateNum]: FILEGETDATENUM.md [FileGetDayOfWeekNum]: FILEGETDAYOFWEEKNUM.md [FileGetHourNum]: FILEGETHOURNUM.md [FileGetMinutesNum]: FILEGETMINUTESNUM.md [FileGetMonthNum]: FILEGETMONTHNUM.md [FileGetSecondsNum]: FILEGETSECONDSNUM.md [FileGetYearNum]: FILEGETYEARNUM.md [FileMonth]: FILEMONTH.md [FileTime]: FILETIME.md [GetDateNum]: GETDATENUM.md [GetDayOfWeekNum]: GETDAYOFWEEKNUM.md [GetDst]: GETDST.md [GetGmtOffset]: GETGMTOFFSET.md [GetHourNum]: GETHOURNUM.md [GetHSeconds]: GETHSECONDS.md [GetMinutesNum]: GETMINUTESNUM.md [GetMonthNum]: GETMONTHNUM.md [GetSecondsNum]: GETSECONDSNUM.md [GetTicks]: GETTICKS.md [GetYearNum]: GETYEARNUM.md [Month]: MONTH.md [SetClock]: SETCLOCK.md [SetDate]: SETDATE.md [SetGmtOffset]: SETGMTOFFSET.md [Time]: TIME.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > SETCLOCK -------------------------------------------------------------------------------- # SETCLOCK Name: SetClock Syntax:     SetClock(INTEGER HOURS, INTEGER MINUTES, INTEGER SECONDS); Description: Sets the system clock. Parameters: HOURS is an integer containing the hour portion of the time to which the clock is set. HOURS is expressed in 24-hour format, which can range from 0 to 23. MINUTES is an integer containing the minutes portion of the time to which the clock is set. MINUTES range from 0 to 59. SECONDS is an integer containing the seconds portion of the time to which the clock is set. SECONDS range from 0 to 59. Return Value: None. Example:     ANALOG_INPUT Hours, Minutes, Seconds;     CHANGE Hours, Minutes, Seconds     {       SetClock(Hours, Minutes, Seconds);       PRINT("Current Time is: %s\n", Time());     } In this example, the Hours, Minutes, and Seconds are specified from an external SIMPL Program. For example, if Hours = 5, Minutes = 10, Seconds = 25, then the output will be Current Time is: 05:10:25. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > SETDATE -------------------------------------------------------------------------------- # SETDATE Name: SetDate Syntax:     SetDate(INTEGER MONTH, INTEGER DAY, INTEGER YEAR); Description: Sets the system date. Parameters: MONTH is an integer containing the month to which the date is set. A valid range is 1 through 12, corresponding to January through December. DAY is an integer containing the day of the month to which the date is set. The range varies from month to month, but always starts at 1. YEAR is an integer containing the year to which the date is set. The year is four digits, i.e. 1999. Return Value: None. Example:     ANALOG_INPUT Month, Day, Year;     CHANGE Month, Day, Year     {       SetDate(Month, Day, Year);       PRINT("Current Date is: %s\n", Date(1));     } In this example, Month, Day, and Year come from a SIMPL program. For example, if Month = 12, Day = 25, Year = 1999, the output from this program will be Current Date = 12/25/1999. Version: X Generation:  SIMPL v1.50.06 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > SETGMTOFFSET > SetGmtOffset -------------------------------------------------------------------------------- # SetGmtOffset Name: SetGmtOffset Syntax:     SIGNED_INTEGER SetGmtOffset(SIGNED_INTEGER GmtOffset); Description: Sets the system GMT Offset. Can be used as an alternative to the GMTOFFSET console command. Parameters: A SIGNED_INTEGER containing the offset in minutes. Valid values are -720 through 780. Return Value: A SIGNED_INTEGER  0: Success -1: Could not set (out of range) Example:     // Set the GMT Offset to -300 minutes (-5 hours)     SIGNED_INTEGER return_code;     return_code = SetGmtOffset(-300);     if(return_code = -1)        print("Could not set GMT Offset, out of range.\n"); Error (-1) is returned. Version: SIMPL+ Version 3.03.00 or later CUZ 3.154 or later required -------------------------------------------------------------------------------- ## Language Constructs & Functions > Time & Date Functions > TIME -------------------------------------------------------------------------------- # TIME Name: Time Syntax: STRING TIME(); Description: Returns a string containing the current system time. Parameters: None. Return Value: The return string contains the time in HH:MM:SS format, in 24-hour time. If a value is not two digits wide, it is padded with leading 0s. Example:     STRING TheTime$[100];     FUNCTION MAIN()     {       TheTime$=TIME();       PRINT("The Time is %s\n", TheTime$);     } An example output from this would be "The Time is 14:25:32". Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > ByRef, ByVal, ReadOnlyByRef > ByRef, ByVal, ReadOnlyByRef -------------------------------------------------------------------------------- # ByRef, ByVal, ReadOnlyByRef NOTE:  Passing STRINGs with BYVAL and BYREF is not allowed in the 2-Series Control System. All STRINGs are passed by referenced in the 2-Series Control System. NOTE:  Passing I/O datatype variables (DIGITAL_INPUT, ANALOG_INPUT and STRING_INPUT) is not allowed in the 2-Series Control System. | KEYWORD | MEANING | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ByRef | Changes made to the variable that is passed to the function actually change the contents of the source variable. Note that any change made to the source variable will be reflected in the function. For example, if an INTEGER is passed ByRef and its state changes, the function will know about the change. It is typically more efficient to pass a variable by reference because space is not taken up by making local copies as with ByVal. Also referred to as "Pass by Reference". | | ByVal | The variable that is passed to the function has a local copy made of it. Changes made to the variable in the function are made on a local copy. The local copy is destroyed when the function terminates. The contents of this variable are a "snapshot" of the contents of the variable that was passed. Unlike Pass by Reference, changes made to the original variable that was passed to the function are not recognized in the function. When an expression is passed, it may only be passed by value since there is no source variable that the ByRef keyword may potentially modify. Also referred to as "Pass by Value". | | ReadOnlyByRef | This performs a Pass by Reference, identical to ByRef, but the compiler catches operations that write to the variable that has been passed. This would be typically be used if a DIGITAL_INPUT or other input type has been passed and which cannot be written. It is also used as a tool to catch unintentional writes to variables that have been passed. | If not specified in the function declaration, variables will be passed by reference if applicable. If the variable cannot be passed by reference (such as an element of an array), it will be passed by value. Any expression will always be passed by value. The following table shows legal access methods for the basic data types when passed to a function. | VARIABLE TYPE | ByVal [LOCAL COPY] | ByRef [SOURCE] | ReadOnlyByRef [SOURCE] | | --------------------------------------- | ------------------ | -------------- | ---------------------- | | ANALOG_INPUT | R, W | R, (E1) | R | | ANALOG_INPUT array | - | R, (E1) | R | | ANALOG_INPUT array element | R,W | - | - | | ANALOG_OUTPUT | R,W | - | R | | ANALOG_OUTPUT array | - | - | R | | ANALOG_OUTPUT array element | R, W | - | - | | BUFFER_INPUT | R, W | R | R | | BUFFER_INPUT array | - | R | R | | BUFFER_INPUT array element | R, W | - | - | | DIGITAL_INPUT | R, W | R, (E1) | R | | DIGITAL_INPUT array | - | R, (E1) | R | | DIGITAL_INPUT array element | R, W | - | - | | DIGITAL_OUTPUT | R, W | - | R | | DIGITAL_OUTPUT array | - | - | R | | DIGITAL_OUTPUT array element | R, W | - | - | | INTEGER | R, W | R, W | R | | INTEGER array | - | R, W | R | | INTEGER array element | R, W | - | - | | LONG_INTEGER | R, W | R, W | R | | LONG_INTEGER array | - | R, W | R | | LONG_INTEGER array element | R, W | - | - | | SIGNED_INTEGER | R, W | R, W | R | | SIGNED_INTEGER array | - | R, W | R | | SIGNED_INTEGER array element | R, W | - | - | | SIGNED_LONG_INTEGER | R, W | R, W | R | | SIGNED_LONG_INTEGER array | - | R, W | R | | SIGNED_LONG_INTEGER array element | R, W | - | - | | STRING | R, W | R, W | R | | STRING array | - | R, W | R | | STRING array element | R, W | - | - | | STRING_INPUT | R, W | R | R | | STRING_INPUT array | - | R | R | | STRING_INPUT array element | R, W | - | - | | STRING_OUTPUT | - | - | - | | STRING_OUTPUT array | - | - | - | | STRING_OUTPUT array element | - | - | - | | STRUCTURE | - | R, W | R | | STRUCTURE element (INTEGER) | R, W | - | - | | STRUCTURE element (LONG_INTEGER) | R, W | - | - | | STRUCTURE element (SIGNED_INTEGER) | R, W | - | - | | STRUCTURE element (SIGNED_LONG_INTEGER) | R, W | - | - | | STRUCTURE element (STRING) | - | - | - | R:  Read access allowed. W:  Write access allowed. (E1):  Generates a RunTime Error, not allowed to be write to INPUT values. The ReadOnlyByRef generates a compile error instead of a RunTime Error. An example of a function declaration that has no parameters and returns no value would be:     FUNCTION PrintText()     {       // Code     } The following is an example of a function declaration that takes an INTEGER and returns a STRING. The INTEGER is passed by value, so it cannot be modified. NOTE:  It is not strictly necessary to use the "ByVal" keyword here. ByVal can be used to make sure that no modifications to the original variable are done by accident within the function.     STRING_FUNCTION ComputeDate(ByVal INTEGER TheMonth)     {       STRING Month$[20];       // Code to compute Month$…       RETURN(Month$);     } The following is an example of a function declaration that takes a STRING array and sorts it and an integer that takes the actual number of elements that are contained in the array. It returns an INTEGER error code:     INTEGER_FUNCTION SortNameInDatabase(STRING Name[],                                         INTEGER NumElements)     {       INTEGER Error;       // Code to sort Names[] and setError…       RETURN(Error);     } -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > Calling a Function -------------------------------------------------------------------------------- # Calling a Function When calling a function where the return is being used, the syntax is:     \ = \([argument_list]); For example,     INTEGER X, ANALOG1, ANALOG2;     STRING Q$[20], B$[50];     X = ComputeChecksum(Analog1, Analog2);     Q$ = DoSomething(Analog1, B$); Are legal. If the return is not going to be used, or there is no return (in the case of a FUNCTION), the syntax is:     \ \([argument_list]); For example,     CALL DoSomethingElse();  (X-Generation or 2-Series) or     DoSomethingElse() ;   (2-Series only) NOTE:  (X-Generation only) Functions do not support recursion, i.e. the code in the body of a function may not contain a call to that function. NOTE:  The keyword, CALL, is required in the X-Generation control system, and optional in the 2-Series control system. CALL may not be used when calling non-user defined functions.   For example:  CALL Print( str, "abc" );   // Illegal -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > Function Definition -------------------------------------------------------------------------------- # Function Definition     \ \ ([argument list])     {       \      [RETURN \;]     } The table shown below demonstrates what \ may be, what it means, and what data may be returned to the caller. Note that in all cases, a RETURN is not required, as the system defaults it to a shown specified value. | | MEANING | RETURN VALUE | | ---------------------------- | -------------------------------------------------- | ------------------------------------------ | | FUNCTION | Returns no data to the caller. | No RETURN | | INTEGER_FUNCTION | Returns an integer value to the caller. | INTEGER expression (default 0) | | LONG_INTEGER_FUNCTION | Returns a long integer value to the caller. | LONG_INTEGER expression (default 0) | | SIGNED_INTEGER_FUNCTION | Returns a signed integer value to the caller. | SIGNED_INTEGER expression (default 0) | | SIGNED_LONG_INTEGER_FUNCTION | Returns a signed long integer value to the caller. | SIGNED_LONG_INTEGER expression (default 0) | | STRING_FUNCTION | Returns a string value to the caller. | STRING expression (default "") | -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > Function Libraries -------------------------------------------------------------------------------- # Function Libraries NOTE:  A function may be placed in the same body of code as the caller. In some cases, the same function needs to be used across several different modules. Although the code could be rewritten in all modules (as was the case with SIMPL+ Version 1.00), SIMPL+ Version 2.00 supports function libraries. A function library is simply a group of functions in a SIMPL+ file. The file is saved as a SIMPL+ Library File (\*.USL), from the Save As dialog in the SIMPL+ editor. In order to include a function library, the #CRESTRON_LIBRARY or #USER_LIBRARY directives are used. The libraries are searched in the order they are included, in case a function name is used in more than one library. The first function found is used. Refer to #CRESTRON_LIBRARY and #USER_LIBRARY  for more information. -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > Function Parameters -------------------------------------------------------------------------------- # Function Parameters NOTE:  Passing [STRINGs] with [BYVAL and BYREF] is not allowed in the 2-Series Control System. All STRINGs are passed by referenced in the 2-Series Control System. NOTE:  Passing I/O datatype variables ([DIGITAL_INPUT], [ANALOG_INPUT] and [STRING_INPUT]) is not allowed in the 2-Series Control System. Functions may contain a list of parameters that are passed by the caller. Typically, data is passed to a function in order to make the code readable, maintainable, and less prone to bugs. SIMPL+ Version 1.00 did not allow data to be passed to functions. The only way to get data into functions was to declare global variables and have the functions reference the global variables. The function argument list contains a comma separated list of arguments. The arguments are of the form:     [ByRef | ByVal] \ \ [ByRef and ByVal][BYVAL and BYREF] are keywords telling the system the read/write permissions and local behavior for the variable in the function. [INTEGER], [STRING][STRINGs] or [STRUCTURE] tells the function the\ type. [BUFFER_INPUT], [STRING_INPUT], [STRING_OUTPUT], and STRING declarations are passed into a function using the STRING type. All other types are passed using the INTEGER type. The function refers to the passed variable as \. Note that for a one-dimensional array, the syntax is \[] and for a two-dimensional array the syntax is \[][]. [STRINGs]: ../Declarations/STRING.md [BYVAL and BYREF]: ByRef%2c_ByVal%2c_ReadOnlyByRef.md [DIGITAL_INPUT]: ../Declarations/DIGITAL_INPUT.md [ANALOG_INPUT]: ../Declarations/ANALOG_INPUT.md [STRING_INPUT]: ../Declarations/STRING_INPUT.md [INTEGER]: ../Declarations/INTEGER.md [STRUCTURE]: ../Declarations/STRUCTURES.md [BUFFER_INPUT]: ../Declarations/BUFFER_INPUT.md [STRING_OUTPUT]: ../Declarations/STRING_OUTPUT.md -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > Returning a Value -------------------------------------------------------------------------------- # Returning a Value The syntax for returning a value from integer and string functions is RETURN \;.   \ To return from a FUNCTION, PUSH, CHANGE, RELEASE or EVENT, the syntax is RETURN. Integer functions include INTEGER_FUNCTION, SIGNED_INTEGER_FUNCTION, LONG_INTEGER_FUNCTION and SIGNED_LONG_INTEGER_FUNCTION. String functions include STRING_FUNCTION. For Integer Functions, any valid integer expression is legal. For example:     RETURN (25);     RETURN (Z + MULDIV(A,B,C) + 100); Are legal (assuming Z, A, B, C, are INTEGERs). If no RETURN statement is present in an integer, 0 is returned. NOTE: If no Return Value is specified within an String_Function, then an empty string will be returned by default. NOTE: RETURN  is a 2-Series only function. For a string function, any valid string is legal (string expressions are not allowed).  For example: STRING str[100]; RETURN ("Hello!\n"); RETURN (str); Are legal (assuming Z is an INTEGER and A$ is a STRING). If no RETURN statement is present in a STRING_FUNCTION, an empty string ("") is returned. In SIMPL Version 3.00, the RETURN statement without arguments can be used in all functions that do not return strings or integers. For example:          INTEGER_FUNCTION MyIntegerFn ( )     {       IF (1)       {       RETURN (1);       }       RETURN (0);     }     LONG_INTEGER_FUNCTION MyLongIntFn ( )     {       IF (1)       {       RETURN (1);       }       RETURN (0);     }     SIGNED_INTEGER_FUNCTION MySignedIntFn ( )     {       IF (1)       {       RETURN (1);       }       RETURN (0);     } SIGNED_LONG_ INTEGER_FUNCTION MySignedLongIntFn ( )     {       IF (1)       {       RETURN (1);       }       RETURN (0);     } STRING_FUNCTION MyStringFn ( )     {       IF (1)       {       RETURN ("abc");       }       RETURN ("def");     }     FUNCTION MyFn ( )     {       IF (1)       {       return;       }     } EVENT {         if (1)             return; } PUSH {         if (1)             return; } RELEASE {         if (1)             return; } CHANGE {         if (1)             return; } -------------------------------------------------------------------------------- ## Language Constructs & Functions > User Defined Functions > User Defined Functions Overview -------------------------------------------------------------------------------- # User Defined Functions Overview A SIMPL+ program may have functions that are defined by users. Typically, a function is defined to modularize code to make repetitive tasks easier to perform or make code easier to read. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > CANCELALLWAIT > CancelAllWait -------------------------------------------------------------------------------- # CancelAllWait Name: CancelAllWait Syntax:     CancelAllWait(); Description: Cancels all WAIT events for the current SIMPL+ program. When an event is cancelled, it is removed from the wait list and will not activate. There is no effect on wait events that have finished running. Parameters: None. Return Value: None. Example:     DIGITAL_INPUT Trig, KillWaits;     PUSH Trig     {       WAIT(1000, FirstWait)  {         PRINT("Wait 1 Triggered!\n");  }       WAIT(2000, SecondWait)  {         PRINT("Wait 2 Triggered!\n");  }     }     PUSH KillWaits     {       CancelAllWait();     } In this example, when Trig is pushed, a 10-second and 20-second event are scheduled. Whichever wait events are still running when KillWaits is triggered, will be removed from the Wait list and will not get activated. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > CANCELWAIT > CancelWait -------------------------------------------------------------------------------- # CancelWait Name: CancelWait Syntax:     CancelWait(NAME); Description: Cancels a specified named WAIT event in the current SIMPL+ program. When an event is cancelled, it is removed from the wait list and will not activate. There is no effect if the wait event has finished running. Parameters: NAME is a name of a previously defined and named WAIT event. Return Value: None. Example:     DIGITAL_INPUT Trig, KillWaits;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }       WAIT(2000, SecondWait) {         PRINT("Wait 2 Triggered!\n"); }     }     PUSH KillWaits     {       Cancelwait(FirstWait);     } In this example, when Trig is pushed, a 10-second and 20-second event are scheduled. When KillWaits is triggered, if FirstWait is still on the wait list, it will be removed from the wait list and will not get activated. SecondWait will activate at the end of the 20-second wait time. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > Overview > Wait Events Overview -------------------------------------------------------------------------------- # Wait Events Overview When writing a SIMPL+ program, it is often desirable to have an event that will be processed a predetermined amount of time after it is triggered. The WAIT event allows a block of code to be executed after a specified amount of time. There are related functions which allow WAITS to be paused, resumed, cancelled, or have their times changed. The system supports up to 200 total timed events that may be running at any given time across all SIMPL+ modules. Timed events include: WAIT, DELAY, and PAUSE statements. A WAIT statement differs from a DELAY in both timing and order of statement execution. In a WAIT statement, the WAIT block executes only after the specified amount of time, but execution proceeds immediately to the statement following the WAIT block.  In a DELAY, all execution is halted until the delay is finished. -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > PAUSEALLWAIT > PauseAllWait -------------------------------------------------------------------------------- # PauseAllWait Name: PauseAllWait Syntax:     PauseAllWait(); Description: Pauses all WAIT events for the current SIMPL+ program. When an event is paused, the timer for it freezes and may later be resumed, retimed, or cancelled. When a wait is resumed, it executes the remaining time from when it was paused until the defined wait time. Parameters: None. Return Value: None. Example:     DIGITAL_INPUT Trig, PauseWaits;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }       WAIT(2000, SecondWait) {         PRINT("Wait 2 Triggered!\n"; }     }     PUSH PauseWaits     {       PauseAllWaits();     } In this example, when Trig is pushed, a 10-second and 20-second event is scheduled. When PauseWaits is triggered, any of the running WAIT events will be halted, but may later be resumed, cancelled, or retimed. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > PAUSEWAIT > PauseWait -------------------------------------------------------------------------------- # PauseWait Name: PauseWait Syntax:     PauseWait(NAME); Description: Pauses a specified named WAIT event in the current SIMPL+ program. When an event is paused, the timer for it freezes and may later be resumed, retimed, or cancelled. When a wait is resumed, it executes the remaining time from when it was paused until the defined wait time. Parameters: NAME is a name of a previously defined and named WAIT event. Return Value: None. Example:     DIGITAL_INPUT Trig, PauseWait;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }       WAIT(2000, SecondWait) {         PRINT("Wait 2 Triggered!\n"; }     }     PUSH PauseWait     {       PauseWait(SecondWait);     } In this example, when Trig is pushed, a 10-second and 20-second event is scheduled. When PauseWait is triggered, the SecondWait event will be paused if it has not already run to completion. It may be later cancelled, resumed, or retimed. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > RESUMEALLWAIT > ResumeAllWait -------------------------------------------------------------------------------- # ResumeAllWait Name: ResumeAllWait Syntax:     ResumeAllWait(); Description: Resumes all WAIT events for the current SIMPL+ program that had been previously paused. The WAIT will execute when the time from when it was frozen until the specified wait time has elapsed. Parameters: None. Return Value: None. Example:     DIGITAL_INPUT Trig, PauseWaits, ResumeWaits;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }       WAIT(2000, SecondWait) {         PRINT("Wait 2 Triggered!\n"; }     }     PUSH PauseWaits     {       PauseAllWait();     }     PUSH ResumeWaits     {       ResumeAllWaits();     } In this example, when Trig is pushed, a 10-second and 20-second event is scheduled. When PauseWaits is triggered, any of the running WAIT events will be halted. When ResumeWaits is triggered, the previously paused waits will resume from when they were paused. For example, if FirstWait and SecondWait were paused at 5-second, when ResumeAllWait is called, FirstWait will have 5-seconds more to execute and SecondWait will have 15-seconds more to execute. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > RESUMEWAIT > ResumeWait -------------------------------------------------------------------------------- # ResumeWait Name: ResumeWait Syntax:     ResumeWait(NAME); Description: Resumes the specified named WAIT event in the current SIMPL+ program that has been previously paused. The WAIT will execute from the time when it was paused until the specified wait time has elapsed. Parameters: NAME is a name of a previously defined and named WAIT event. Return Value: None. Example:     DIGITAL_INPUT Trig, PauseWaits, ResumeWaits;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }       WAIT(2000, SecondWait) {         PRINT("Wait 2 Triggered!\n"; }     }     PUSH PauseWaits     {       PauseAllWait();     }     PUSH ResumeWait     {       ResumeWait(FirstWait);     } In this example, when Trig is pushed, a 10-second and 20-second event is scheduled. When PauseWaits is triggered, any of the running WAIT events will be halted. When ResumeWaits is triggered, the FirstWait event that was previously paused will resume from when it was paused. For example, if FirstWait was paused at 5-seconds, when ResumeWait(FirstWait) is called, FirstWait will have 5-seconds more to execute. SecondWait will still be paused. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > RETIMEWAIT > RetimeWait -------------------------------------------------------------------------------- # RetimeWait Name: RetimeWait Syntax:     RetimeWait(INTEGER TIME, NAME); Description: Changes the time for a wait event in progress. When a WAIT is retimed, the WAIT is restarted. For example, if a 5-second wait is 3-second in, and it is retimed to 10-second, a full 10-seconds must elapse before the WAIT triggers. Parameters: TIME is an integer that specifies the new wait time in hundredths of a second. If time is set to 0, the event will occur immediately. NAME is a name of a previously defined WAIT event. Return Value: None. Example:     DIGITAL_INPUT Trig, ChangeWaitTime;     PUSH Trig     {       WAIT(1000, FirstWait) {         PRINT("Wait 1 Triggered!\n"); }     }     PUSH ChangeWaitTime     {       RetimeWait(500, FirstWait);     } In this example, when Trig is pushed, a 10-second event is scheduled. If ChangeWaitTime is activated while FirstWait is still running, the time will be reset to 5-seconds. If FirstWait has expired, no action will be taken. Version: X Generation:  SIMPL v1.20.01 and later 2-Series:  SIMPL v2.01.05 and later -------------------------------------------------------------------------------- ## Language Constructs & Functions > Wait Events > WAIT > Wait -------------------------------------------------------------------------------- # Wait Name: Wait Syntax:     Wait(INTEGER |LONG_INTEGER TIME[, NAME])     [{]       \     [}] NOTE: There is no semicolon after a WAIT statement because it has a clause or block following it. Description: Adds an event to a list to be executed in TIME hundredths of a second. Giving a WAIT a name is optional, but to cancel, pause, resume, or retime a wait, a name must be specified. A currently running WAIT will finish before being entered into the WAIT list again. For example, if in an endless WHILE loop, a second WAIT will only begin after the first finishes. When the system encounters a WAIT, the event is put into the WAIT scheduler. The SIMPL+ module continues to execute without interruption. At some point, a task switch will occur (either due to event termination or other means, refer to [Task Scheduling Changes and Consequences], [Task Switching for 2-Series Control Systems] and [Task Switching for X-Generation (CNX) Control Systems]). The WAIT schedule is checked by the operating system after a task switch, and if a wait event needs to be serviced, it is run and then terminates. Note that the module may task switch away while inside the WAIT, just like in other events. A WAIT statement differs from a DELAY in both timing and order of statement execution. In a WAIT statement, the WAIT block executes only after the specified amount of time, but execution proceeds immediately to the statement following the WAIT block.  In a DELAY, all execution is halted until the delay is finished. Parameters: TIME is a long_integer, expressed in hundredths of a second. For example, 525 specifies a wait time of 5.25 seconds. NAME is an optional name given to the WAIT event. It has the same syntax as a variable name. Note that you cannot put two separate WAIT statements in the same SIMPL+ program that have the same NAME (this will cause a compilation error). NOTE:  (2-Series Only) The only variable types that are allowed to be used within a Wait Statement block are global variables and variables declared locally within the Wait Statement's block. Local variables declared within the function containing the Wait Statement are not allowed. NOTE:  A semicolon should not be used at the end of the WAIT statement.  If a semicolon is placed immediately after the wait statement, a compiler error will result. If braces are not following the WAIT statement, only the statement immediately following will be part of the WAIT statement.  See example below. Example:     LONG_INTEGER WaitTime;     DIGITAL_INPUT StopVCR;     ANALOG_INPUT SysWait;     STRING_OUTPUT VCR$;     PUSH StopVCR { WAIT (SysWait, VCR_Stop) // correct { VCR$ = "\x02STOP\x03"; } WAIT (SysWait, VCR_Stop) // correct VCR$ = "\x02STOP\x03"; // this is the only statement for this WAIT statement VCR$ = "\x02PLAY\x03"; // will NOT be included in WAIT statement WAIT (SysWait, VCR_Stop); // ERROR - semicolon should NOT be used { VCR$ = "\x02STOP\x03"; } } FUNCTION MyFunc() { while ( 1 ) { // statements (will keep executing during the wait statement) Wait( 500 ) { // statements (execute once for each wait statement occurence) } // statements (will keep executing during the wait statement) } } In this example, a VCR is triggered to go into STOP, but the STOP command is delayed based upon a time specified by an analog input to the SIMPL+ program. Version: X Generation SIMPL v1.20.01 and later 2-Series: SIMPL v2.01.05 and later [Same as X Generation SIMPL v1.20.01] however local variables are allowed within WAIT statements. [Task Scheduling Changes and Consequences]: ../../Task_Switching/Task_Scheduling_Changes_and_Consequences.md [Task Switching for 2-Series Control Systems]: ../../Task_Switching/Task_Switching_for_2-Series_Control_Systems.md [Task Switching for X-Generation (CNX) Control Systems]: ../../Task_Switching/Task_Switching_for_CNX_Control_Systems.md -------------------------------------------------------------------------------- ## Obsolete Functions > System Interfacing Functions -------------------------------------------------------------------------------- # System Interfacing Functions - [GetCIP] - [GetCresnet] - [GetSlot] - [IsSignalDefined] - [SendCresnetPacket] - [SendPacketToCPU] - [SetCIP] - [SetCresnet] - [SetSlot] [GetCIP]: Language_Constructs_&_Functions/System_Interfacing/GetCIPDev.md [GetCresnet]: Language_Constructs_&_Functions/System_Interfacing/GetCresnetDev.md [GetSlot]: Language_Constructs_&_Functions/System_Interfacing/GetSlotDev.md [IsSignalDefined]: Language_Constructs_&_Functions/System_Interfacing/IsSignalDefined.md [SendCresnetPacket]: Language_Constructs_&_Functions/System_Interfacing/SendCresnetPacket.md [SendPacketToCPU]: Language_Constructs_&_Functions/System_Interfacing/SendPacketToCPU.md [SetCIP]: Language_Constructs_&_Functions/System_Interfacing/SetCIPDev.md [SetCresnet]: Language_Constructs_&_Functions/System_Interfacing/SetCresnetDev.md [SetSlot]: Language_Constructs_&_Functions/System_Interfacing/SetSlotDev.md -------------------------------------------------------------------------------- ## Operators > Arithmetic Operators -------------------------------------------------------------------------------- # Arithmetic 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 | -------------------------------------------------------------------------------- ## Operators > Bitwise Operators -------------------------------------------------------------------------------- # Bitwise Operators 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. -------------------------------------------------------------------------------- ## Operators > 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 = ','); -------------------------------------------------------------------------------- ## Operators > 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 > Overview > Operators Overview -------------------------------------------------------------------------------- # 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 | | | | | |----|----|----|----| | 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 | 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 -------------------------------------------------------------------------------- ## 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. -------------------------------------------------------------------------------- ## Operators > 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. -------------------------------------------------------------------------------- ## Programming Environment > BookMarks > 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 > 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: \.usp  -  SIMPL+ User Module (Never Deleted) \.usl  -  SIMPL+ User Library (Never Deleted) \.ush  -  SIMPL+ User Module Header File (Never Deleted - File is written upon SIMPL+ Module compilation) SPlusWork Directory will contain the following files: \.inf  -  SIMPL+ Module Information File  (Remains after a successful compilation) \.spl  -  SIMPL+ intermediary file  (Remains after a successful compilation) \.h  -  SIMPL+ intermediary file  (Remains after a successful compilation) \.o  -  SIMPL+ intermediary file  (Remains after a successful compilation) \.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 > 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 > 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 > EditMenu > 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 > EditSelectAll > 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 > 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 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 > FindNext > 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 > 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 -------------------------------------------------------------------------------- # 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 > 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. -------------------------------------------------------------------------------- ## Programming Environment > Target Selection > 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 > Windows Color Manager > 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 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. -------------------------------------------------------------------------------- ## Revision History > SIMPL+ Revisions -------------------------------------------------------------------------------- # SIMPL+ Revisions Download the latest revisions from [www.crestron.com/updates]. TBD [www.crestron.com/updates]: http://www.crestron.com/updates -------------------------------------------------------------------------------- ## Revision History > 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 | -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Compact Flash Functions > TP 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 > 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 > 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 > Controlling Program Flow Branching > TP Controlling-Program-Flow-Branching > 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 > if‑else -------------------------------------------------------------------------------- ## 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 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. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Controlling Program Flow Branching > TP Controlling-Program-Flow-Branching > 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 Loops > TP Controlling-Program-Flow-Loops > 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 > for Loops -------------------------------------------------------------------------------- ## 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 (\ = \ to \ step \)\ {\ // 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); /\* 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); -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Controlling Program Flow Loops > TP Controlling-Program-Flow-Loops > while and do‑until Loops -------------------------------------------------------------------------------- ## 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)\ {\ \} 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\ {\ \} 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. 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. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Controlling Program Flow Loops > TP Controlling-Program-Flow-Loops > 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 > Debugging > TP 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("\",\); The **\** 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 > For Whom is this Guide Intended > 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 > Operators, Expressions and Statements > TP Operators, Expressions, and Statements > 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]. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Operators, Expressions and Statements > TP Operators, Expressions, and Statements > 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]. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Operators, Expressions and Statements > TP Operators, Expressions, and Statements > 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 -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Quick Start > Making it Work > Making it Work -------------------------------------------------------------------------------- # 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. 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+. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Quick Start > Writing Your First SIMPL Plus Program > Writing Your First SIMPL+ Program: "Hello World" -------------------------------------------------------------------------------- # 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. 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 -------------------------------------------------------------------------------- ## 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 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 > Compiler Directives -------------------------------------------------------------------------------- ## 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} 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. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > The Structure of a SIMPL Plus Program > TP Structure-of-a-SIMPLPlus-Program > 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 “\”\ #CRESTRON_LIBRARY “\” 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 > 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 \,\,…\;\ ANALOG_INPUT \,\,…\;\ STRING_INPUT \[size],\[size],...\[size];\ BUFFER_INPUT \[size],\[size],...\[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 \,\,…\;\ ANALOG_OUTPUT \,\,…\;\ STRING_OUTPUT \,\,…\; 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 > \ -------------------------------------------------------------------------------- ### \ 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 > 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 > 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 \\ {\ \} 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 > \ -------------------------------------------------------------------------------- ### \ 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\ {\ \} 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\ {\ \} 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\ } ### \ The Global Event A special form of event exists, which is triggered anytime any of the inputs to the SIMPL+ module changes. This is simply a shortcut for having to build a compound event manually which includes all the inputs separated by commas in a `CHANGE` event declaration. Access this special event function by using the `EVENT` keyword, as follows. EVENT\ { // this code runs anytime anything\   // on the input list changes\ } Be careful when using this global event function. If the user has a SIMPL+ program in which a change on any input causes the same code to execute, this type of event is useful. However, if additional inputs are added at a later time, remember that this event function exists, and it is caused when these new inputs change as well. This may not be desirable. \ Function Main --------------------------------- `Main` is a special case of a user‑defined function. The `Main` function is executed when the control system initializes (boots up) and is never called again. In many cases, the `Main` function is used to initialize variables; it may not contain any statements at all. However, in some cases, a loop may be placed in the `Main` function to perform a continuous action. Refer to the following example, and note that this example uses a `while` loop construct, which is discussed in [Controlling Program Flow: Loops]. Function Main()\ {\ Integer x;\ String LocalString[50000]; x = 0; While (1) {//\ code in here runs continuously LocalString = GatherByLength(2, MyDelimitedString, GATHER_TIMEOUT); If(Len(LocalString) = 0)//timeout occurred\ {\ ClearBuffer(MyDelimitedString);\ Print "Timeout occurred in Delimited string. \n");\ Break:\ }//code to work with received string}} This loop runs continuously for as long as the control system is on. If a construct like this is used, it is recommended that a `ProcessLogic` or `Delay` function in the loop be included to allow the logic processor a chance to handle the rest of the system. If one of these statements is not included, the operating system forces a task switch at some point in time. These concepts are discussed in detail in [Understanding Processing Order]. [Working with Strings]: ../Working_With_Strings/TP_Working-with-Strings.md [Working with Data (Variables)]: ../Working_With_Data/TP_Working-with-Data-(Variables).md [Understanding Processing Order]: ../Understanding_Processing_Order/TP_Understanding-Processing-Order.md [Controlling Program Flow: Loops]: ../Controlling_Program_Flow_Loops/TP_Controlling-Program-Flow-Loops.md -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Understanding Processing Order > TP Understanding-Processing-Order -------------------------------------------------------------------------------- # Understanding Processing Order ## How SIMPL+ and SIMPL Interact Advanced SIMPL programmers should be familiar with how logic is processed in SIMPL programs. This guide does not attempt to explain this concept here, but it does detail how SIMPL+ programs fit into the picture. However, a couple of definitions may be helpful. **Logic Wave** ‑ The act of propagating signals from the input to the output of a logic symbol. In a typical program, a single logic wave may include the processing of many symbols. **Logic Solution** ‑ An arbitrary number of logic waves, processed until the state of all signals in the program have settled to a stable (i.e. unchanging) state. In general, when a SIMPL+ event function is triggered, it is processed to conclusion in a single logic wave. That is, if this event caused a change to one of the output signals, that signal would be valid one logic wave after the event was triggered. In this simple case, a SIMPL+ program acts identically to a SIMPL logic symbol from a timing standpoint. In addition, for multiple SIMPL+ events triggered on the same logic wave (whether or not they are in the same module), these events multi-task (run at the same time) and complete before the next wave. As SIMPL+ programs become more complex and processor intensive however, this general rule may no longer apply. Instead, the operating system may determine that too much time has elapsed and temporarily suspend the SIMPL+ program while it continues to process the SIMPL logic (which may also include other SIMPL+ programs). For example, if an event function must run through a loop 2000 times before completing, the processor may decide to perform a task switch and process other logic before completing the loop. This task‑switching ability has the benefit of not freezing up the rest of the program while a particularly intensive calculation is proceeding. After the completion of the current logic solution, the SIMPL+ program that was exited continues from where it left off. ## Forcing a Task Switch There may be times in programming when it is necessary to force a task switch to occur. For example, when a digital_output is set high, it normally is not propagated to the SIMPL program until the SIMPL+ completes. To guarantee that the digital signal is asserted, force the system to switch from the SIMPL+ module back into the SIMPL program. There are two ways to force a task switch: with the **ProcessLogic** function or the **Delay** function. To provide an immediate task switch out of the current SIMPL+ module, use **ProcessLogic**. When the logic processor enters this module on the next logic solution, execution begins with the line immediately following. An immediate task switch also results from **Delay**, but the SIMPL+ module does not continue executing until the time specified has elapsed. The **Delay** function is discussed in greater detail in [Working with Time]. [Working with Time]: ../Working_With_Time/TP_Working-with-Time.md -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions -------------------------------------------------------------------------------- # User Defined Functions The previous section details how to use system functions in SIMPL+. When programming, there may be a need to create functions of your own to simplify your programs. These functions are called user‑defined functions. User‑defined functions perform exactly like system functions with the only exception in that they must be defined before they are used. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > Function Definitions -------------------------------------------------------------------------------- ## Function Definitions Since user‑defined functions are created by the user (the SIMPL+ programmer), the user must make sure that the SIMPL+ compiler knows about these functions before the program tries to call them. This is accomplished by creating a function definition, which is different from a function call. Remember from the discussion of system functions that a function call is used to invoke a function. A function definition tells the SIMPL+ compiler what the function does. User functions are used for several reasons. It is not desirable to create one function that performs every task for the entire program. To help better organize program modules, creating several smaller functions makes programming easier to read and understand, and debug. User‑defined functions can also be called by any other function. Rather than have the same programming logic written out in several functions, one function can be defined with this logic and then called by any other function within the module. This will also greatly reduce the module’s size. To help the reusability of functions, any number of variables can be passed to functions. Variables are passed to functions through the function’s argument list. This is also called parameter passing, or function arguments. Function arguments can be thought of as passing a value into a function. Other variables or literal values can be passed to function arguments. Function arguments are another way of defining local variables. The difference between declaring a local variable within the function and declaring one as part of the parameter list is that the function argument will have the value of the calling function’s variable copied into it. It is also useful for a function to return a value. A function might be written to compute a value. Another function might want to perform a task and return an error code that can be evaluated by the calling function. Functions can only return at most one value, namely integers or strings. When defining a function, the returning value will determine what type of function to declare. The different types of functions are: `FUNCTION`, `INTEGER_FUNCTION` and `STRING_FUNCTION`. For the 2‑series and newer compilers, `LONG_FUNCTION`, `SIGNED_INTEGER`, and `SIGNED_LONG_FUNCTION` are also available. The syntax of a SIMPL+ function call is as follows: FUNCTION MyUserFunction( [parameter1][, parameter2][, parametern] )\ {\ \} INTEGER_FUNCTION MyUserIntFunction( [parameter1][, parameter2][, parametern] )\ {\ \} STRING_FUNCTION MyUserStrFunction( [parameter1][, parameter2][, parametern] )\ {\ \} The `FUNCTION` keyword is used to tell the SIMPL+ compiler that what follows is the definition of a function and not a function call. The `FUNCTION` keyword also specifies that there will be no return value for this function. `INTEGER_FUNCTION` and `STRING_FUNCTION` specify that an integer or string value will be returned as the result of the function. These keywords are also called the function type. The next keyword is a name provided by the SIMPL+ programmer that will become the name for this user function (called the function name). Be sure to use a unique name and not an existing SIMPL+ keyword, system function, or a previously declared variable name. Otherwise, a compile syntax error will result. Following the function name is the function’s argument list. If no arguments are needed within this function, then the list can remain empty. Otherwise, a parameter is defined by giving a variable type and name (i.e., `INTEGER myIntArgument`). One or more functions are possible by separating each with a comma. Function definitions are global to the SIMPL+ module in which they are defined. That is, any event function, the `Function Main`, or even another user‑defined function can call a user‑defined function that has been defined in the same SIMPL+ module. Functions defined in other modules are not accessible. When calling a function, it is critical not only that that function has been defined in the SIMPL+ module, but also that this function definition occur before the line of code which calls the function. For example, consider the following. INTEGER x; PUSH someSignal\ {\ call MyUserFunction1();\ x = MyUserFunction2( x, 10 );} FUNCTION MyUserFunction1()\ {\ print("This is MyFunction1 runnning!\n");} INTEGER_FUNCTION MyUserFunction2( INTEGER arg1, STRING arg2 )\ {\ print("This is MyFunction2 runnning!\n");} This code causes a compile error, because the function `MyUserFunction1` has been called before it has been defined. This can easily be remedied by reversing the order: INTEGER x; FUNCTION MyUserFunction1()\ {\ print("This is MyFunction1 runnning!\n");} INTEGER_FUNCTION MyUserFunction2( INTEGER arg1, STRING arg2 )\ {\ print("This is MyFunction2 runnning!\n");} PUSH someSignal\ {\ call MyUserFunction1();\ x = MyUserFunction2( x, 10 );} This program compiles without any problems. Due to this dependence on order, the SIMPL+ module template that appears each time a new program is created provides a place to put function definitions. Notice that this section comes after the input/output and variable definitions, but before the event and main functions. Following the layout suggested by the template should prevent most of these errors. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > Defining Local Variables In Functions -------------------------------------------------------------------------------- ## Defining Local Variables In Functions The concept of local variables was introduced in the section [Working with Data (Variables)]. In this section we will discuss the topic in greater detail and present a number of examples. What is a local variable? A local variable is a variable (i.e. an integer or string) with a limited life span and limited scope. You can think of global variables as being immortal. That is, for as long as the control system is plugged in and the program is running, global variables retain their values unless a programming statement modifies them. In addition, global variables can be accessed (either to use their value or to modify them) anywhere in a SIMPL+ program. Here is a simple example: DIGITAL_INPUT go;\ INTEGER i,j,k; // define 3 global integers FUNCTION sillyFunction()\ {\ i = j \* 2;\ k = i ‑ 1;} FUNCTION anotherSillyFunction()\ {\ j = i + k;} PUSH go\ {\ i = 1;\ j = 2;\ k = 3;\ Print("i = %d, j = %d, k = %d\n", i, j, k);\ Call sillyFunction();\ Print("i = %d, j = %d, k = %d\n", i, j, k);\ Call anotherSillyFunction();\ Print("i = %d, j = %d, k = %d\n", i, j, k);} In this program, it should be clear to see that both of the functions defined, as well as the push event, have access to the three global integers `i`, `j`, and `k`. Local variables, on the other hand, can only be accessed within the function in which they are defined. If another user‑defined function or event function tries to access a local variable defined elsewhere, a compiler error will be generated. In addition, as soon as the function completes execution, all of the functions' local variables are destroyed. This means that any value they contained is lost. The next time this function is called the local variables are re‑created. Creating local variables is identical to creating global variables, except that the declaration statement is placed inside of the function definition, as follows: FUNCTION localExample()\ {\ INTEGER i, count, test;\ STRING s[100], buf[50];} -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > Passing Variables to Functions as Arguments -------------------------------------------------------------------------------- ## Passing Variables to Functions as Arguments The last section describes how to make your programs easier to read and maintain by defining variables local to functions. However, this does not change the fact that by their very nature most functions require access to one or more variables that have been declared elsewhere in the program, either as global variables or as local variables in a different function. The question is, how can your function access these variables. As we have already seen, global variables are available everywhere in a program, thus you can simply use such variables to share data between functions and the rest of the program. This is considered bad programming practice, however, and often leads to programs that are hard to read and even harder to debug. Functions can also access any input/output signals defined in the program, but as these signals can be thought of as global variables, this too is not considered good programming practice. Instead of using global variables to share data, we instead use the concept of passing arguments (also known as parameters) into functions. Arguments can be thought of as an ordered list of variables that are passed to a function by the calling function (the term calling function simply refers to the scope of the code statement which calls the function in question). To define a function’s parameters, you list them inside the parentheses following the function name. A typical function definition would look like this: FUNCTION some_function (INTEGER var1, INTEGER var2, STRING var3)\ {\ INTEGER localInt;\ STRING localStr[100]; var1 = var1 + 1;\ localInt = var1 + var2;\ localStr = left(var3, 10); } Notice that the function shown above has three arguments, named `var1`, `var2`, and `var3`. `var1` and `var2` are integers, while `var3` is a string. Shown below is an example of how to call this function from elsewhere in your program: Call some_function( intVal1, 5+1, stringVal1); Here we are assuming that the variable `intVal1` has been defined as an integer earlier in the program, as has the string variable, `stringVal1`. Also note that the second argument is a constant, and not a variable at all. This simply means that inside `some_function`, the value of `var2` will be set to `6`. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > ByRef, ByVal, and ReadOnlyByRef -------------------------------------------------------------------------------- ### ByRef, ByVal, and ReadOnlyByRef When defining a function’s argument list, there are optional keywords you can use which give you greater control over the behavior of the arguments. These keywords are ByRef, ByVal, and ReadOnlyByRef. What do these keywords mean? Essentially they describe the way that SIMPL+ passes variables to the function. When a function argument is defined as ByRef, any variable that is passed to this argument will pass enough information about itself to allow the function to modify the value of the original variable. The term ByRef is used because we say a reference to the original variable is passed to the function. This reference can be thought of the memory location where the original variable lives. When a function argument is defined as ByVal, only the value of the variable and not the variable itself is passed to the function, so the original variable cannot be modified within the function. As an example, below is a function, which takes two strings as arguments. It inserts one string into the other at a specified character location: Note: When passing STRING arguments by value, you only need to specify the ByVal keyword for 2-series modules. 3-Series and 4-Series STRINGS are passed by value by default, unless ByRef is used. 2-Series Example: FUNCTION insertString(ByRef STRING string1, ByVal STRING string2, ByVal INTEGER position) { STRING leftpart[20], rightpart[20]; leftpart = left(string1,position); rightpart = right(string1,position); string1 = leftpart + string2 + rightpart; } 3-series and 4-Series Example: FUNCTION insertString(ByRef STRING string1, STRING string2, ByVal INTEGER position) { STRING leftpart[20], rightpart[20]; leftpart = left(string1,position); rightpart = right(string1,position); string1 = leftpart + string2 + rightpart; } In this example, note that only the first string argument, string1, was defined as ByRef. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > Functions That Return Values -------------------------------------------------------------------------------- ## Functions That Return Values To this point all user‑defined functions we have discussed have had one thing in common: when the functions are finished executing they do not return a value to the calling code. This statement is ambiguous, because some of the functions do modify the values of their arguments, and thus these modified variables can be used by the calling procedure. However, the term return value is used to describe the core value, which is returned from the function to the calling procedure. Many system functions discussed earlier in this manual have return values. For example, here are some statements that use the return values of functions: String1 = itoa(int1);\ position = find(“Artist”,CD_data);\ int3 = max(int1, int2); For clarity, here are some example statements using system functions that do not have return values: Print(“Variable int1 = %d\n”,int1);\ ProcessLogic();\ CancelWait(VCRWait); It should be clear that, at least as far as system functions go, whether or not a function returns a value depends largely upon what that function is designed to do. For example, the `itoa` function would not be very valuable if it did not return a string, which could then be assigned to a variable, or used inside of an expression. On the other hand, the `Print` function simply outputs text to the console for viewing, and thus no return value is needed. Allowing a user‑defined function to return a value is extremely useful, as it allows such functions to be used in flexible ways, such as inside of an expression. To enable a function to return a value, use a modified version of the function keyword, as shown below: STRING_FUNCTION strfunc1();  //function returns a string\ INTEGER_FUNCTION intfunc1(); //function returns an integer\ FUNCTION func1();            //function has no return value Clearly, functions defined using the `STRING_FUNCTION` keyword will return a string value, and those defined using the `INTEGER_FUNCTION` keyword will return an integer value. Function declared using the `FUNCTION` keyword would have no return value. Once a function has been declared using the appropriate function type, it is the responsibility of the programmer to ensure that the proper value is returned. This is accomplished using the return function. To illustrate this, examine the following function example, which raises one number to the power determined by the second argument, and returns the result. INTEGER_FUNCTION power(INTEGER base, INTEGER exponent)\ {\ INTEGER i, result; if (base = 0)\    return (0); else if (exponent = 0)\    return (1); else {\    result = 0; // initialize result\    for (i = 1 to exponent)\       result = result + result \* base;    return (result);}} To use this function in a program, simply call the function just like you would any built‑in system function. Here are a few usage examples: Print(“5 raised to the power of 3 = %d\n”,power(5,3)); x = power(y,z); As a second example, we shall build a function which appends a simple `checksum` byte onto the end of a string. As was mentioned earlier in this manual, `checksum`s are used by many devices to provide a basic form of error checking. In this example, the `checksum` is formed by simply adding up the values of each byte in the command string and then appending the equivalent ASCII character of the result onto the string itself. If the `checksum` value is larger than a single byte (255 decimal), we simply ignore the overflow and use the lower 8-bits of the result. DIGITAL_INPUT control_device1, control_device2;\ STRING_OUTPUT device1_out, device2_out;\ STRING device1_cmd[20], device2_cmd[20], tempCmd[20]; STRING_FUNCTION appendChecksum(STRING command)\ {\ INTGEGER checksum, i;   // define local variables checksum = 0;    // initialize variable for (i = 1 to len(command)) // calculate the sum\    checksum = checksum + byte(command,i); return(command + chr(checksum)); //append the byte } PUSH vcr_play\ {\ vcr_out = appendChecksum(“PLAY”);} PUSH vcr_stop\ {\ vcr_out = appendChecksum(“STOP”);} In this example, the system function, `byte`, is used inside the function to get the numeric value of each byte in the string. After the `checksum` has been calculated, the `chr` function is used to append the corresponding ASCII character to the end of the command string. Realize that this example is useful for just one (very simple) type of `checksum`. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > User Defined Functions > TP User-Defined-Functions > Function Libraries -------------------------------------------------------------------------------- ## Function Libraries You are likely to find that the longer you program in SIMPL+ the more you will need to repeat code you have already written. For example, a function that converts the temperature from Celsius to Fahrenheit might come in handy in more than one job. Clearly, code that has many applications is best placed inside of a function. Remember, however, that unlike system functions, which are globally available, user‑defined functions are only available inside of the SIMPL+ program in which they exist. If you need to use a user‑defined function in more than one SIMPL+ program, you must copy and paste it from one program to another. While this technique works, it can lead to problems when, for example, you find a bug in the function and fix it one program but forget to change it elsewhere. To solve this problem, SIMPL+ has introduced the concept of function libraries. Simply put, a function library is a collection of user‑defined functions placed in a separate file. A library can consist of only a single function, or can consist of every function you have ever written. More likely, you will organize your libraries so that each one contains related functions. For example, you may create a string handling library, which consists of a number of functions that perform useful operations on stings. Once a function has been included inside of a function library, it now becomes accessible to all SIMPL+ modules that are made aware of it. To make a SIMPL+ program aware of a particular library, you must use the `#USER_LIBRARY`. To include a user library within a SIMPL+ module, the syntax is as follows: #USER_LIBRARY "MyStringFunctionLib" Note that the file extension (.usl in this case) is left out. The above example refers to the function library called `MyStringFunctionLib.usl`. Any number of user libraries can be included within a SIMPL+ module. Special function libraries that are created by Crestron and made available to all customers can be used in a similar manner. The only difference is the use of the `#CRESTRON_LIBRARY` compiler directive in place of `#USER_LIBRARY`. Crestron function library files end with the extension .csl. [Working with Data (Variables)]: ../Working_With_Data/TP_Working-with-Data-(Variables).md#All -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Using SIMPL Windows vs. SIMPL Plus > Using SIMPL vs. SIMPL+ -------------------------------------------------------------------------------- # Using SIMPL vs. SIMPL+ SIMPL+, while exciting and powerful, does present the programmer with somewhat of a dilemma, namely, when to program in SIMPL and when in SIMPL+. The answer of course is not cut-and-dry, and just about any task can be accomplished entirely in one language or the other. However, the true power of Crestron control system programming is unleashed when the strengths of both environments are harnessed simultaneously. First, almost every program to be written will have some elements of SIMPL. Any time a button is needed to act as a toggle, or it is necessary to interlock a group of source buttons, it is generally simpler to handle these tasks with SIMPL. SIMPL+ is advantageous for more complex and algorithmic tasks, such as building complex strings, calculating checksums, or parsing data coming from another device. In addition, complex decision-making, especially when dealing with time and date, is generally much easier to handle in SIMPL+. Finally, data storage and manipulation may be better suited to SIMPL+ than to SIMPL (though many SIMPL programs have been written to do these chores). Of course, ultimately the decision as to how to program is up to the individual. Personal preference certainly comes in to play. With practice, a happy medium can be found that makes programming both efficient and fun. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Using System Functions > TP Using-System-Functions -------------------------------------------------------------------------------- # Using System Functions In order to make programming in SIMPL+ simpler and more powerful, the concept of functions is introduced. A function is essentially a more complicated programming task that has been predefined and given a name. Many of the examples in previous sections of this document have used special types of functions called system functions (or built‑in functions). To employ system functions, use the following format. returnValue = FunctionName(Parameter1, Parameter2,...); The above syntax is called a function call, because it tells the function to cause/perform an action. Notice that there are three elements to a function call. First, it is identified by `FunctionName`, which must be unique for every system function. The function name itself is followed by a comma‑separated parameter list enclosed in parentheses. Each function may have a fixed number of parameters, a variable number of parameters, or no parameters at all. These parameters provide the means to supply information to a function. For example, the itoa function converts an integer value into its ASCII equivalent, which is very useful for creating strings to control switchers. The single parameter to this function would be the integer value that needs to be converted. Parameters can be any valid SIMPL+ expression. Consider the statements: returnValue = itoa(154);         // constant param\ returnValue = itoa(input_num);   // variable param\ returnValue = itoa(x\*5-4);       // general expression param All are valid function calls. The variable to the left of the equal sign in the above function calls is used to hold the return value of the function. This value can be either an integer or a string, depending on the nature of the function. Clearly, if a given function returns an integer value, an integer variable must be used to accept this value and a string variable for those functions that return strings. In the itoa examples shown above, the return value is the ASCII string which represents the number being converted. Thus, `returnValue` in this case must be a string variable. Some functions do not return any values at all. Thus it is not reasonable to assign a variable to a function as shown above. In addition, when using functions that do return values, sometimes the return value may not be needed. In both cases, use the `Call` keyword: Call FunctionName(Parameter1, Parameter2, ...); In this case, if the function being called does return a value, it is ignored. Be aware as well that some functions may need to return more than one value. Since functions can only have at most a single return value, there are some functions that modify the values of the parameters that are passed to it. SIMPL+ provides a large number of system functions, which are listed under a number of categories in the latest revision of the SIMPL+ Language Reference Guide. Many of these system functions are used as examples throughout this manual. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > What is Needed to Use SIMPL Plus > What is Needed to Use SIMPL+? -------------------------------------------------------------------------------- # What is Needed to Use SIMPL+? SIMPL+ version 2.0 requires a CNX-series control processor and SIMPL v1.23 or later. SIMPL+ version 3.0 accompanies SIMPL v2.00 or later, and may be used to program either a 2-Series control system or a CNX-series control system. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > What is SIMPL Plus > What is SIMPL+? -------------------------------------------------------------------------------- # What is SIMPL+? SIMPL+® is a language extension to SIMPL. It does not replace SIMPL, but instead it enhances it. With SIMPL+ it is now possible to use a procedural “C-like” language to code elements of the program that were difficult, or impossible with SIMPL alone. A SIMPL+ program is a module that directly interacts with the control system. In order to interact with the control system, a module must contain a few essential elements. The first element is a starting point.  A starting point is needed for two reasons.   - First, it serves as a convenient place to initialize any global variables that are declared within the module.   - Second, any functionality that the module needs to perform on its own (instead of being triggered through an event), can be instantiated here.   Another element is event processing.  In order for a SIMPL+ module and a control system to interact, they must be able to send and receive signals to and from one anothe. Input and output (I/O) signals are declared within the module are then tied directly to the control system. Input signals are sent from the control system and are received within the SIMPL+ module. Output signals are sent from the SIMPL+ module to the control system. Events are functions that are triggered through input signals from the control system. I/O signals can be either digital, analog or serial and are declared within the SIMPL+ module. Events tell the SIMPL+ module that something has changed within the control system and allows the module to perform any action accordingly. . -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Where Can I Get More Information > Where Can I Get More Information? -------------------------------------------------------------------------------- # Where Can I Get More Information? This guide should contain all the information needed to program in SIMPL+. For specific information about the language syntax, refer to the latest revision of the SIMPL+ Language Reference Guide . -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Working with Data (Variables) -------------------------------------------------------------------------------- # Working with Data (Variables) Programming is really the manipulation of data. Examples of data in a program are the `switcher` input and output numbers, the name of the next speaker and the amount of time left before the system shuts down automatically. This section covers the different data types available in SIMPL+. ## Input/Output Types Input/output variables are used to transfer data between SIMPL+ modules and the surrounding SIMPL program. Each input or output variable in SIMPL+ is connected directly to a signal in the SIMPL program. SIMPL programmers should already be familiar with the three signal types available in that language: digital, analog, and serial. The table below takes a closer look at the type of data conveyed by these signal types. | Signal Type | Data | Example | |-------------|----------------------|-----------------------------------| | Digital | Single bit | Button push/release | | Analog | 16-bit (0 to 65,535) | Volume level | | Serial | Up to 255 bytes | Serial data input from a COM port | SIMPL Signal Styles {cellspacing="0"} This table illustrates that digital signals only transfer a single bit of information between SIMPL+ and SIMPL. Of course this makes sense, as digital signals only have two possible states (on and off). Obviously, analog and serial signals allow the transfer of much more information per signal. Depending on the application, it may be more convenient to generate an analog signal in SIMPL and connect it to a SIMPL+ program, rather than connecting a large number of digital signals and setting some variable based on which was pressed last (though both methods should work). ### Digital Inputs/Outputs Digital signals comprise the bulk of signals in a typical SIMPL program. In SIMPL+ they are used mainly to trigger events on the rising‑ or falling‑ edge of the signal, though they can also be used in expressions. The state (or value) of a digital signal is always either 1 or 0 (also referred to as On or Off). In SIMPL+, assigning a value of 0 to a digital signal turns it Off. Assigning it any non-zero value will turn it On (for clarity, in most cases, use the value 1). ### Analog Inputs/Outputs Analog signals are used in SIMPL to accomplish tasks for which digital signals are inadequate. Typical examples include volume control and camera pan/tilt control. In SIMPL+, analog signals take on even greater importance since they provide an easy way of transferring data (16 bits at a time) into and out of SIMPL+ modules. In SIMPL+, analog signals are treated much as they are in SIMPL. They are 16-bit numbers that can range between 0 and 65,535 (unsigned) or ‑32768 and +32,767 (signed). Signed and unsigned numbers are discussed in detail in [Working with Data (Variables)]. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > String Inputs/Outputs and Buffer Inputs -------------------------------------------------------------------------------- ### String Inputs/Outputs and Buffer Inputs Perhaps the greatest advantage that SIMPL+ provides is related to string handling. In SIMPL, serial data can be generated dynamically and placed on serial signals. However, one problem that arises is due to the transient nature of these signals. Simply put, serial signals are invalid except for the time between when they are created and when they reach the next symbol. With careful programming this does not cause problems, but it requires a good understanding of SIMPL. SIMPL+ makes working with serial data much simpler by storing this data into temporary string variables. When a serial signal is connected to a SIMPL+ module and the SIMPL program causes data to be sent via this signal, the SIMPL+ program copies the data from this signal into local memory. The data is kept there until the SIMPL program changes it. By storing the serial data into a string variable, SIMPL+ programmers can now perform tasks on strings that were difficult or impossible with SIMPL alone. For example, it is easy to evaluate a string and then add a `checksum` byte on the end to insert or remove characters from a string, or to parse information out of a string for use elsewhere. Functions that are designed to work explicitly with string signals and string variables are discussed in detail in the latest revision of the SIMPL+ Language Reference Guide. Serial data is also unique in that unlike digital or analog signals, the data may not appear at one time, but instead it can stream in (e.g., if it comes from a COM port). This raises an interesting problem, namely, what happens if a command string coming in from a device is not picked up as one piece, but rather is broken up into two or more pieces? The problem arises in that a string input is completely replaced each time new data is detected on the input. To account for this, an alternate type of serial input type may be used, the buffer input. The buffer input differs from the string input in that serial data that comes in is appended onto data that already exists in the buffer, instead of replacing it. This type of behavior is critical for performing sophisticated string parsing and manipulation when dealing with streaming data. Refer to [Working with Strings] for a detailed discussion of buffer inputs. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Signal Scope -------------------------------------------------------------------------------- ### Signal Scope Signals are global throughout the entire SIMPL program and to any SIMPL+ program to which they are connected. In a SIMPL+ program, the values of digital, analog, and string inputs are read (their values can be evaluated). However, their values cannot be changed from within the SIMPL+, thus they are considered read‑only. Buffer inputs can be read from and modified. Digital and analog output signals in SIMPL+ can be read and modified. String outputs can be modified, but cannot be read back. To understand this, the user must realize what is being seen when looking at the contents of an output variable in a SIMPL+ program. The value of any output is the value of the signal as seen by the outside SIMPL program at that instant. This is critical considering that SIMPL+ does not necessarily propagate outputs to the SIMPL program each time they are changed in the program. As a general rule, assume that analog and serial outputs are propagated at the time they are assigned new values. However, digital signals are not propagated until a task switch occurs. This explains reading values of analog and digital outputs, but why is it that string outputs cannot be read? The reason has to do with the nature of serial signals in SIMPL. Namely that these signals do not actually store strings in them, but rather point to locations in memory where a string exists. Since the data stored at a particular location in memory can change at some later time, there is no guarantee that the string data is still there. As a result, SIMPL+ does not allow a string output to be examined. Examine the following code example. DIGITAL_OUTPUT d_out;\ ANALOG_OUTPUT a_out;\ STRING_OUTPUT s_out; PUSH someEvent\ {\ d_out = 1; // set this digital output to ‘on’\ a_out = 2000; // set this analog output to 2000\ s_out = "hello"; // set this string output to "hello" if (d_out = 1) // this WILL NOT be true until the Print ("d_out is on\n"); // next task-switch if (a_out = 2000)       // this WILL be true Print ("a_out = 2000"); if (s_out = "hello")    // this WILL NOT be true due to the Print ("s_out is hello"); // nature of serial signals ProcessLogic(); // force a task-switch if (d_out = 1) // NOW this is true Print ("d_out is on\n");\ } Function Main()   // initialization\ {\ d_out=0;\ a_out = 0;} In this example, the digital output, `d_out`, and the analog output,` a_out`, are set to `0` on system startup in the `Function Main`. In the `push` function, the first conditional `if` statement evaluates to `False` because the digital output signal, `d_out`, is considered `Off` until this value is propagated to the SIMPL program. With digital outputs, this does not happen until the SIMPL+ program performs a task switch. The analog and string outputs, on the other hand, are propagated as soon as they are assigned new values. Thus the second `if` condition evaluates to `True` and the subsequent `print` statement is executed. The third `if` statement can still evaluate to `False`, however, due to the nature of serial signals in SIMPL, as previously described. Notice the `ProcessLogic` function call in the last example. This function forces a task switch from SIMPL+ to the SIMPL logic processor. This causes the digital signal to be propagated out to the SIMPL program. The next time the logic processor passes control back to this SIMPL+ program, it picks up where it left off. As a result, the fourth `if` condition evaluates to True, thus executing the print statement. Note: The `if` language construct is described in detail in [Controlling Program Flow: Branching]. Evaluation of True and False expressions are covered in [Operators, Expressions, and Statements]. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > All About Variables -------------------------------------------------------------------------------- ## All About Variables In addition to input and output signals, additional variables can be declared that are only used inside the SIMPL+ program. That is, the outside SIMPL program has no knowledge of these variables and no access to them. These variables are critical for use as temporary storage locations for calculations. Unless otherwise specified with a compiler directive, all variables in SIMPL+ are volatile, which means that they do not remember their values if power is lost. The compiler directive, `#DEFAULT_NONVOLATILE`, can be used to change this behavior so that the variable's values are retained after power is lost. Notably, it is generally a good idea to explicitly initialize variables to some value before using them, except in the cases where it becomes necessary to take advantage of their non‑volatility. An obvious place to do this is in `Function Main`. SIMPL+ allows for two different types of variables: integers and strings. In addition, variables of either type may be declared as one‑ or two‑dimensional arrays. The following sections explain these topics in detail. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Integers -------------------------------------------------------------------------------- ### Integers Integers contain 16‑bit whole numbers. That is, they can range between 0 and 65,535 (unsigned, refer to paragraph after example) and cannot contain a decimal point. SIMPL programmers may recognize that this range is identical to that of analog signals. This is because analog signals are also treated as 16‑bit values. Integers are declared as follows: INTEGER \, \,…,\; Depending on how they are used, integers can either be unsigned or signed. Unsigned integers have values between 0 and 65,535. Signed integers have values between ‑32768 and +32767. In reality, there is no difference between a signed and unsigned integer, the difference is solely in how the control system views them. That is, for any given value, that number can be thought of as either being a signed number or an unsigned number. Depending upon which operations are perform on a number, the control system decides whether to treat that number as signed or unsigned. When an integer has a value of between 0 and 32767, it is identical whether it is considered signed or unsigned. However, numbers above 32767 may be treated as negative numbers. If they are, they will have a value of x ‑65536, where x is the unsigned value of the number. This means that the value 65,535 has a signed value of ‑1, 65534 is ‑2, etc. This scheme is referred to as two’s complement notation. Why is all this signed/unsigned discussion important? Well, in most cases, it can be ignored and things work out fine. However, for those instances when it does make a difference, it pays to understand how to debug programs that are not working as expected. In control system programming, often there is not a need for negative numbers (e.g., how often is a switcher switched to input number ‑12 ?). As a result, the most common operations treat integers as unsigned and it becomes necessary to use special signed operators or functions when treating numbers as signed. The table after this paragraph lists operators and functions that are unsigned and those that are signed. Any operators or functions that are not shown here do not need special consideration. | Description | Unsigned Operators/Functions | Signed Operators/Functions | |----|----|----| | Less than | \< | S\< | | Less than or equal to | \<== | S\<= | | Greater than | \> | S\> | | Greater than or equal to | \>= | S\>= | | Integer division | / | S/ | | Maximum | Max() | SMax() | | Minimum | Min() | SMin() | Unsigned/Signed Operators and Functions {cellspacing="0"} Examine the following: INTEGER j, k; Function Main()\ {\ j = 2;\ k = -1; // this is the same as k = 65535 if (j \> k) // this will evaluate to FALSEPrint( “j is bigger as unsigned numbers\n” ); if (j S\> k) // this will evaluate to TRUEPrint( “j is bigger as signed numbers\n” );} In this example, the first condition, `j > k`, evaluates to `False` and the `Print` statement does not execute. This is because the `>` operator performs an “unsigned greater than” operation. If both `j` and `k` are converted to unsigned values, `j` remains at `2`, but `k` becomes `65,535`, and thus `k` is obviously not smaller than `j`. The second condition, `j S> k`, evaluates to `True`, because this time the “signed greater than” operator was used. Examine one more example: INTEGER a, b, c, d; Function Main()\ {\ a = 100;\ b = ‑4; c = a / b; // c = 0 (100/65532)\ d = a S/ b; // d = ‑25 (100/‑4)} Notice that `c` calculates to `zero` because the `/` operator is unsigned. It treats the variable `b` as `+65,532`. Since the `/` operator truncates the decimal portion of the result, `c` becomes `zero`. In regard to the variable `d`, since the signed division operator `S/` was used, `b` is treated as `‑4` and the result is `‑25`. A final note regarding signed/unsigned integers, if an operation results in a number that is greater than 65,535 that number overflows and the value wraps around again starting at zero. This allows certain operators (e.g. +, ‑, and \*) to operate with no regard to sign (the result is accurate when thinking of the numbers as signed or unsigned). This also means that when trying to add (or multiply) two unsigned numbers and the result is greater than 65,535, the answer may not be what is expected. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Strings -------------------------------------------------------------------------------- ### Strings String variables are used to hold multiple characters in a single variable. The term string is used to illustrate the act of stringing together a number of characters to produce words, sentences, etc. Typically strings in SIMPL+ are used to hold things such as serial commands, database records, and so on. Strings are declared as follows: STRING \, \,…,\; The number in square brackets following the variable name defines the size of the string variable. When declaring strings, choose a size that is large enough to hold any amount of data that might be needed, but that is not overly large so as to waste space. That is, it is unnecessary to set the variable size to 100 characters when a given variable in an application does not contain more than 50 characters. Working with strings is not unlike working with other variable or signal types. To assign a value to a string, for example, do the following: STRING myString[50];\ myString = "Tiptoe, through the tulips\n"; In the example above, a variable called `myString` is declared, which can contain up to 50 characters of data. The value, `Tiptoe, through the tulips\n`, is the value being assigned to the variable. The double-quotation marks surrounding the data defines a literal string expression. That is, a string expression which is defined at compile‑time (when the program is compiled) and cannot change during run-time (while the program is running). Also note the `\n` at the end of this string literal. This represents a newline, or a carriage return followed by a line feed. This character combination is used often, so a shortcut was developed. For a complete list of similar shortcuts, refer to the latest revision of the SIMPL+ Language reference Guide. Finally, note that the square brackets were not included after the variable name, as was done when it was declared. When assigning a value to a string, that value is always assigned starting at the first character position. It is important to note that the length of the this value does not exceed total length allocated for `myString` (in this case, 50 characters). If the declared variable is not large enough to hold the data being assigned to it, the data is truncated to as many characters as the string can hold. Also, when the program is being executed, a string overflow error will be reported within the control system’s error log. The example above is useful, but does not really begin to tap the enormous string‑generating capabilities of SIMPL+. A common task in control system programming is the control of an audio/video matrix switch. To control such a router, often it is necessary to specify the input and output which make up the desired matrix crosspoint. As an example, assume the device to be controlled expects to see a command in a format, shown as follows: IN\OUT\\\ This protocol allows the input and output to be specified as numbers. For example, to switch `input 4` to `output 10`, the command would be as follows: IN4OUT10\\ Where `` represents the carriage return and line feed characters. Obviously, for a router of any significant size, the number of possible crosspoints can grow very large. Thus creating a literal string expression for each case would be very inefficient. Instead, build the control string dynamically as the program runs. An easy way to do this is through the use of the string concatenation operator (`+`). Note that this is identical to the addition operator, but the SIMPL+ compiler is smart enough to know whether integers are added or string expressions are concatenated. This is addressed in the following code: DIGITAL_INPUT do_switch;\ STRING_OUTPUT switcher_out[10];\ INTEGER input, output; PUSH do_switch\ {\ switcher_out = "IN" + itoa(input) + "OUT" + itoa(output) + "\n";} In this example, the `+` operator is used to concatenate multiple string expressions. The itoa function has been used, which converts an integer value (in this case from analog input signals) into a string representation of that number (e.g. 23 becomes “23”). There is an alternate way to build strings in SIMPL+. The `MakeString` function provides functionality similar to the concatenation operator, while providing a bit more power and flexibility. The following line is equivalent to the concatenation statement above: MakeString( switcher_out, "IN%dOUT%d\n", input, output ); This syntax is a bit more confusing. The first argument to the `MakeString `function, `switcher_out`, is the destination string. This is where the resulting string created by `MakeString` is placed. The second argument, the part embedded in double-quotation marks, is the format specification. This determines the general form of the data. Notice how the constant parts of the string are entered directly. The interesting thing about the format specification is the `%d` sequences, which are known as type specifiers. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Variable Scope -------------------------------------------------------------------------------- ### Variable Scope Variable declarations in a SIMPL+ program can be either global or local. Global variables are defined in the Define Variables section of the code, and exist throughout the entire SIMPL+ program. This means that any event function or user‑defined function can reference and modify global variables. When the value of a global variable is being set or modified, it is reflected throughout the entire program. Local variables are defined inside a function declaration and exist only inside that particular function. In other words, if a local variable, `byteCount`, were defined inside of a function, `CalcChecksum`, any reference to `byteCount`, outside of the scope of this function (e.g. in another function) will result in a compiler syntax error. Note that different functions can use the same variable names when defining local variables. Take a look at the following example: // simple function to add up all the bytes in a\ // string and append the sum as a single byte\ // onto the original string.\ String_Function CalcChecksum(STRING argData)\ {\ INTEGER i, checksum; checksum = 0; for (i = 1 to len(argData))\ checksum = checksum + byte(argData,i); return (argData + chr(checksum));} In this example, `i` and `checksum` are local variables that only exist inside the function, `CalcChecksum`. This example also introduces an additional way to implement a local variable: by passing it as an argument to the function, as was done with the `STRING` variable, `argData`. The concept of local variables and argument passing is discussed in detail in the section [User Defined Functions]. While the use of global variables may seem simpler, local variables can help keep your programs better organized and easier to debug. A significant disadvantage of global variables is that you must be careful each time you use or modify a variable that it does not have an adverse effect on another part of the program. Since local variables can only be used inside of a function, this is not a concern. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Data > TP Working-with-Data-(Variables) > Arrays -------------------------------------------------------------------------------- ## Arrays When `INTEGER` or `STRING` variables are declared, the user may also declare them as one‑ or two‑dimensional (Integers only) arrays. An array is a group of data of the same type arranged in a table. A one‑dimensional array can be thought of as a single row with two or more columns, while a two-dimensional array can be thought of as a table with multiple rows . In SIMPL+, arrays are declared as follows. INTEGER myArray1[15]    // 1-D integer array with 16 elements\ INTEGER myArray2[10][3] // 2-D integer array with 11x4 elements\ STRING myArray3[50][8]  // 1-D string array with 9 elements The first two examples above define `1D` and `2D` integer arrays, respectively. The last example looks like it declares a `2D` array of strings, yet the comments states that it actually declares a `1D` array of strings. Recall that in [Working with Data (Variables)][1], it was necessary to define the maximum size of the string in square brackets, which is the same notation used for arrays. So, in the example above, nine-element array of 50‑byte strings is being declared. The user cannot declare a `2D` array of strings in SIMPL+. Another question should have come to mind from the above examples. That is, why does declaring `myArray1[15]` create an array with 16 elements instead of 15? The answer is that array elements start at 0 and go to the declared size (15 in this case). This fact makes for an easy transition to SIMPL+ for programmers of other languages (some of which start at 0 and others which start at 1). That is, if the user is comfortable with treating arrays as starting with element 0, then the user can continue programming in this manner. If however, the user has used languages, which treat the first element in an array as element 1, then the user may want to use that notation instead. To reference a particular element of an array when programming, use the variable name followed by the desired element in square brackets. Using the arrays declared in the example above, the following statements are all valid in SIMPL+. j = 5;                 // set an integer variable to 5\ myArray1[3] = j;       // set the 3rd element of the array to 5\ myArray1[j\*2] = 100;   // set the 10th element of the array\                        // to 100 myArray2[j][1] = k;    // set the j,1 element of myArray2 to\                        // the value of k m = myArray2[j][k-1];  // set the variable m to the value in\                        // the j,k‑1 element of myArray2 myArray3[2] = "test";  // set the 3rd element of the string\                        // myArray3 to "test" From these examples, it should be clear that the user may use constants, variables, or expressions (discussed in [Operators, Expressions, and Statements]) inside of the brackets to access individual array elements. Array elements can appear on either side of the assignment (`=`) operator. That is they can be written to (left side) or read from (right side). Of special interest is the notation used for storing a value into the string array `myArray3`. Notice that only one set of brackets was used here even though two sets of brackets are needed when declaring the array. Remember that the first set of brackets in the declaration specified the size (in characters) of each string element. Also recall from earlier in this section, that the size field is not included when referring to strings. For example, refer to the following. myString = "hello!";   // we do not use the size brackets here\                        // to assign a value to a string variable As a result, when working with string arrays, only use one set of brackets, which refer to the array element, not the string size. [Working with Data (Variables)]: #Integers [Working with Strings]: ../Working_With_Strings/TP_Working-with-Strings.md [Controlling Program Flow: Branching]: ../Controlling_Program_Flow_Branching/TP_Controlling-Program-Flow-Branching.md [Operators, Expressions, and Statements]: ../Operators,_Expressions_and_Statements/TP_Operators,%20Expressions,%20and%20Statements.md [User Defined Functions]: ../User_Defined_Functions/TP_User-Defined-Functions.md [1]: #Strings -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Strings > TP Working-with-Strings > Working with Strings -------------------------------------------------------------------------------- # Working with Strings In [Working with Data (Variables)] and [Operators, Expressions, and Statements] the concept of the **`BUFFER_INPUT`** was discussed. This section provides a more in-depth treatment of working with incoming serial data. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Strings > TP Working-with-Strings > `BUFFER_INPUT` -------------------------------------------------------------------------------- ## `BUFFER_INPUT` To review what was discussed earlier, serial data entering a SIMPL+ program may be treated as either a **`STRING_INPUT`** or as a **`BUFFER_INPUT`**. What is the difference, and which one should be used? The difference between a **`STRING_INPUT`** and **`BUFFER_INPUT`** is quite simple. The value of a **`STRING_INPUT`** is always the last value of the serial signal that feeds it from the SIMPL program. This means that every time new data is generated on the serial signal in the SIMPL program, the **`STRING_INPUT`** variable in the SIMPL+ program changes to contain that data; any data that was previously contained in that variable is lost. **`BUFFER_INPUT`**s on the other hand do not lose any data that was stored there previously. Instead, any new data that is generated onto the serial signal in the SIMPL program is appended to the data currently in the **`BUFFER_INPUT`** variable. To make this concept even clearer, consider the following simple example. The SIMPL program shown below contains two Serial Send symbols, each one triggered by a button press. The outputs of these symbols are tied together so that both symbols can generate a string onto the same serial signal. Next this signal is connected in two places to the SIMPL+ module. The first input is mapped to a **`STRING_INPUT`** and the second is mapped to a **`BUFFER_INPUT`**. The declaration section for this module should appear as follows. STRING_INPUT theString[100];\ BUFFER_INPUT theBuffer[100]; NOTE: The Serial Send symbol simply generates the static text defined in its parameter field onto the output serial signal whenever the trigger input sees a rising signal. The table below shows the state of these two input variables in response to button presses. | Action | theString | theBuffer | |--------------------|------------|--------------------------| | system initializes | empty | empty | | button 1 pressed | “Now is” | “Now is” | | button 2 pressed | “the time” | “Now is the time” | | button 1 pressed | “Now is” | “Now is the time Now is” | **States of Two Input Variables** {cellspacing="0"} From this table, notice that each time the serial signal changes, **theString** assumes this value and the old data stored there is lost. On the other hand, **theBuffer** retains any old data and simply appends the new data onto the end. Each application should dictate whether it is appropriate to use a **`STRING_INPUT`** or a **`BUFFER_INPUT`**. In general, use **`STRING_INPUT`**s when the serial signal that is feeding it is being driven from a logic symbol like a Serial Send, Analog to Serial, or Serial Gather. In these cases, the serial data is issued on a single logic wave. Therefore, it is certain that the entire string is copied into the **`STRING_INPUT`**. NOTE: A logic wave is the time needed for a signal to propagate from the input to the output of a single logic symbol. This concept is discussed fully in [Understanding Processing Order]. If, on the other hand, the signal feeding into the SIMPL+ program comes from a streaming source such as a serial port, use a **`BUFFER_INPUT`**, which can gather up the data as it dribbles in. To solidify this concept, consider another example. Say the program is written for a CD jukebox, which is capable of sending text strings containing the current song information. Typical data received from this device might appear as the following. Artist=Frank Sinatra, Track=My Way, Album=Very Good Years\ Where the **\** at the end of the string represents a carriage return character. This is a relatively long string of data and it is quite possible, even probable, that the operating system would not remove the entire string from the serial port in one piece. This is due to the fact that the control system checks the state of the serial ports very often and removes any data that is found there. Since this data takes some time to reach the port (depending on the baud rate), it is likely that the port’s input buffer is collected before the whole string is there. If there was a serial signal called **jukebox_in** connected to the rx terminal on the COM port definition, the program might be written as follows. first pass: jukebox_in = "Artist=Frank Sinatra, Trac" second pass: jukebox_in = "k=My Way, Album=Very Good Yea" third pass: jukebox_in = "rs\" If this signal, **jukebox_in**, were then connected to a **`STRING_INPUT`** of a SIMPL+ program, it is likely that the string might not be seen as one complete piece. Thus the artist’s name, the track name, and the album name might not be parsed out for display on a touchpanel. On the other hand, if a **`BUFFER_INPUT`** were used instead, this buffer would collect the data as it arrived. Therefore, after the processor read the port the third time, this **`BUFFER_INPUT`** would contain the complete string. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Strings > TP Working-with-Strings > Removing Data From Buffers -------------------------------------------------------------------------------- ## Removing Data From Buffers Once data has been routed into a **`BUFFER_INPUT`**, techniques are required to extract data from it. Typically the first thing to be done with data on a **`BUFFER_INPUT`** is to pull off a completed command and store it into a separate variable. For example, most data that comes from other devices are delimited with a certain character (or characters) to denote the end of the command. In many instances a carriage return (or carriage return followed by a line feed) is used. The **getc** function is the most basic way to remove data from a buffer. Each call of **getc** pulls one character out of the buffer and returns that character’s ASCII value as the function’s return value. Characters are removed from the buffer in the order they arrived. Thus the first character in becomes the first character out. This function now provides the ability to extract data until the desired delimiter is seen. For example, the following code is read data from the buffer until a carriage return is seen. BUFFER_INPUT data_in[100];\ INTEGER nextChar;\ STRING temp[50], line[50]; CHANGE data_in // trigger whenever a character comes in\ {\ do\ {nextChar = getc(data_in); // get the next character\ temp = temp + chr(nextChar);\ if (nextChar = 0x0D) // is it a carriage return?\ {line = temp;\ temp = "";}} until (len(data_in) = 0) // empty the buffer} Function Main()\ {\ temp = "";} Notice that a **do‑until** loop was used in the example above. Every time a change event is triggered for the **data_in** buffer, it is uncertain that only one character has been inserted. In fact, many characters may have been added since the last change event. Due to this possibility, continue to pull characters out of the buffer with **getc** until the buffer is empty, which is what the expression **(len(data_in) = 0)** reveals. Also notice from the example that the extracted character is stored into an integer. This is because **getc** returns the ASCII value of the character, which is an integer. On the next line, the **chr** function is used to convert that value into a one‑byte string, which can be added to temp. Although this example should work for real‑world applications, there is a potential problem should multiple lines of data come in on the same logic wave. Should this happen, only the last complete line is stored into **line** and the rest is lost. To account for this, make **line** into a string array and store each subsequent line into a different array element. Another possibility is that any code that is needed to further act upon the data could be built directly into this loop. Thus removing the need to store more than one line of data. Once the data has been removed from the buffer and stored in a known format (in this case, one complete command from the device), the desired data can be extracted. Using the example above where the data was coming from a CD jukebox, the following example could be used to extract the artist, track, and album title. BUFFER_INPUT jukebox[100];\ STRING_OUTPUT artist, track, album;\ INTEGER startPos;\ STRING searchStr[20], tempStr[100]; CHANGE jukebox\ {\ do\ {tempStr = tempStr + chr(getc(jukebox));\ if ( right(tempStr,1) = "\r" )\ {searchStr = "Artist=";\ startPos = Find(searchStr,tempStr);\ if (startPos) { // was the string found?\   startPos = startPos + len(searchStr);\   artist = mid(tempStr, startpos,\             Find(",",tempStr,startpos) ‑ startpos);\   searchStr = "Track=";\   startpos = Find(searchStr,tempStr) + len(searchStr);\   track = mid(tempStr, startpos,\             Find("\r",tempStr,startpos) ‑ startpos);\   searchStr = "Album=";\   startpos = Find(searchStr,tempStr) + len(searchStr);\   album = mid(tempStr, startpos,\             Find("\r",tempStr,startpos) ‑ startpos);\   tempStr = "";  }} } until (len(jukebox) = 0);} Function Main()\ {\ tempStr = "";} This example introduces two new system functions, which are extremely useful for string manipulation, the **Find** and **Mid** functions. To search for the existence of a substring inside of another string, use **Find**. If it is located, the return value of the function is the character position where this string was found. If the substring was not found, then **Find** returns zero. Notice that towards the top of the example the program checked to see if the substring **Artist=** is found in the string. If it is not, then assume that the incoming data was of another format and there is no need to bother looking for the other search strings (**Track=** and **Album=**). [Working with Data (Variables)]: ../Working_With_Data/TP_Working-with-Data-(Variables).md [Operators, Expressions, and Statements]: ../Operators,_Expressions_and_Statements/TP_Operators,%20Expressions,%20and%20Statements.md#Inputs, [Understanding Processing Order]: ../Understanding_Processing_Order/TP_Understanding-Processing-Order.md -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Time > TP Working-with-Time > Working with Time -------------------------------------------------------------------------------- # Working with Time Up until now, this manual has discussed elements of the SIMPL+ language that have no concept of time. This means that each statement in a SIMPL+ program executes after the previous statement is completed. There are times when programming where there is a need to have control over exactly when the statements in the program execute. This section deals with those language constructs. ## Delay The **Delay** function pauses the execution of the current SIMPL+ for the time specified in the parameter field. As with most time values in SIMPL+, this time value is specified in hundredths of seconds. The following program causes the program to stop for five seconds before resuming. PUSH startMe\ {\ Print("I’m starting now...");\ Delay(500);     //this equals 5 seconds\ Print("and I’m ending 5 seconds later.\n");} It is important to realize that the control system never allows a SIMPL+ program to lock up the rest of the system for any significant amount of time. Thus, whenever a delay function is reached, the control system performs a task switch, meaning that the execution of the current SIMPL+ module stops momentarily as the natural flow through the SIMPL program continues. In this case, even though the SIMPL+ program has stopped for five seconds, other code in the overall SIMPL program (including standard logic symbols and other SIMPL+ modules) continues to operate normally. The concept of task switching is covered in more detail in the section [Understanding Processing Order]. ## Pulse The **Pulse** function is used to drive a digital output signal high for a specified amount of time. Once again, the time is specified in hundredths of seconds. When a **Pulse** statement is executed, the digital output signal specified is driven high and a task switch occurs. Such a task switch is necessary in order for the rest of the SIMPL program to recognize that the digital signal has indeed gone high. After the time specified has expired, the digital output is driven low and another task switch occurs. The following program causes the digital output signal, **preset_1**, to be pulsed for a half a second. #DEFINE_CONSTANT PULSE_TIME 50 DIGITAL_OUTPUT preset_1, preset_2, preset_3; PUSH some_input\ {\ Pulse(PULSE_TIME, preset_1);} The **Pulse** function is very similar in operation to the SIMPL One Shot symbol. In fact, in many cases, it may be more convenient (or more sensible) to simply connect a One Shot, or Multiple One Shot symbols to the output signals of a SIMPL+ module. Also notice that unlike the **Delay** function, **Pulse** does not cause a pause in the execution of the SIMPL+ code. Therefore, the statements that follow the **Pulse** execute immediately and do not wait for the expiration of the pulse time. -------------------------------------------------------------------------------- ## SIMPL Plus Tutorial > Working With Time > TP Working-with-Time > Wait Events -------------------------------------------------------------------------------- ## Wait Events Wait events in SIMPL+ allow operations that are somewhat similar to the Delay SIMPL logic symbol. The syntax for a Wait event is as follows. Wait (wait_time [, wait_name])\ {\ \} This syntax defines a Wait event to occur at some time in the future, defined by the value of **wait_time**. While the Wait event is pending execution, it is said to have been scheduled. The Wait event may have an optional name, which can be used to refer back to the event elsewhere in the code. When a Wait event definition is reached during execution, the execution of the statements inside the braces (these braces are not needed if the event is only one statement long) is deferred until the time defined by **wait_time** has expired. Until this occurs, the remainder of the SIMPL+ program executes. If a Wait event definition is nested inside of a loop, it is possible that it can be reached multiple times before it even executes once. If a Wait event is pending (i.e., has been scheduled, but not executed), it is not scheduled again until it has been completed. Once a Wait event has been scheduled to execute at some later point in time, various operations can be performed on the event before it actually executes. However, only named Wait events can be modified in this manner, since it is necessary to use the name to refer to the event. The table on the next page lists the available functions, which can operate on Wait events. | Function | Description | |----|----| | CancelWait(name) | Removes the named wait from the schedule. The code never executes. | | CancelAllWait() | Removes all pending waits from the schedule. | | PauseWait(name) | Stops the timer for the named wait. The code does not execute until the timer is started again using ResumeWait(). | | ResumeWait(name) | Resumes the timer for the named wait, which had been paused earlier. | | PauseAllWait() | Similar to PauseWait(), but acts on all pending wait events. | | ResumeAllWait() | Similar to ResumeWait(), but acts on all paused wait events. | | RetimeWait(time, name) | Sets the time for a pending wait event to the value specified. | Functions Available During Wait Events {cellspacing="0"} This example shows a typical use of wait events. Here, the **SYSTEM ON** button starts a power up sequence and the **SYSTEM OFF** button likewise starts a power down sequence. #DEFINE_CONSTANT PULSETIME 50 // half second DIGITAL_INPUT system_on, system_off;\ DIGITAL_OUTPUT screen_up, screen_down, lift_up, lift_down;\ DIGITAL_OUTPUT vcr_on, vcr_off, dvd_on, dvd_off;\ DIGITAL_OUTPUT vproj_on, vproj_off;\ DIGITAL_OUTPUT vproj_video1, vproj_video2, vproj_rgb;\ DIGITAL_OUTPUT lights_pre_1, lights_pre_2, lights_pre_3; PUSH system_on\ {\ CancelWait(sysOffWait); // cancel the system off wait event Pulse(2000, screen_down); // lower screen for 20 sec.\ Pulse(9500, lift_down); // lower lift for 9.5 sec. Wait (1000, sysOnWait1) // 10 second delay\ {Pulse(PULSETIME, vcr_on);\ Pulse(PULSETIME, dvd_on);\ Pulse(PULSETIME, lights_pre_1);\ Pulse(PULSETIME, vproj_on);} Wait (1500, sysOnWait2) // 15 second delay pulse(PULSETIME, vproj_video);} // end of push event PUSH system_off\ {\ CancelWait(sysOnWait1);\ CancelWait(sysOnWait2); Pulse(2000, screen_up);\ Pulse(PULSETIME, vproj_off);\ Pulse(PULSETIME, vcr_off);\ Pulse(PULSETIME, dvd_off); Wait(500, sysOffWait)\ {Pulse(9500, lift_up);\ Pulse(PULSETIME, lights_pre_3); } } // end of push event Notice that in this example, the **CancelWait** function was used to cancel any pending waits when the **SYSTEM ON** or **SYSTEM OFF** buttons were pressed. This is analogous to using the reset input on the Delay symbol in SIMPL. [Understanding Processing Order]: ../Understanding_Processing_Order/TP_Understanding-Processing-Order.md -------------------------------------------------------------------------------- ## Task Switching > Task Scheduling Changes and Consequences > Task Scheduling Changes and Consequences -------------------------------------------------------------------------------- # Task Scheduling Changes and Consequences NOTE: the following applies to 2-series firmware 3.137 and higher. The previous scheduling algorithm method for SIMPL+ events caused unexpected results when writing multiple files simultaneously to compact flash.  We will describe both the old and new algorithms.  This advanced topic assumes that you are familiar with the 2-series task-switching topic [Task Switching for 2-Series Control Systems]. NOTE: Also refer to [Task Switching for X-Generation (CNX) Control Systems] for a discussion of task switching in that environment. Overview One of the premises of a SIMPL+ module is that it has to appear to be the same as any other logic gate in terms of logic delays.  That means that the SIMPL+ code should transfer its inputs into outputs in one logic wave.  This is not always possible due to what the programmer has coded into the SIMPL+ module.  Because the programmer can put delays or loops in his code, the SIMPL+ code is limited in the amount of time it can run before logic resumes.  This slice of time is currently 20 milliseconds.    Initial Design In the initial design for the 2-series, the SIMPL+ code ran at the lowest priority in the system.  This priority level was chosen to prevent SIMPL+ code from blocking other code from running.  For example, if the programmer used a “while(1)” loop without any delays, no lower priority code would ever run.  The mechanism for getting SIMPL+ to run as a logic gate required the logic processor to pause to allow for the SIMPL+ code to start running.  The logic processor would wait for a maximum of 0.5 seconds before resuming.  If the SIMPL+ task has not started after waiting 0.5 seconds, the processor generates a “SIMPL+ Event Timeout” error message.  This is caused by other parts of the system occupying the processor besides the logic processor.   Also, in the initial design, the SIMPL+ code was marked as non-preemptive.  This means that while the SIMPL+ code was running, no other process in the system could interrupt its execution.  The code ran until it finished, release control temporarily back to the control system (delay() or ProcessLogic()), or its allotted time of 20 ms ran out.  This is the portion that may interfere with the low level operations of the file system.  Low-level function calls dealing with file operations would mark the current task as non-preemptive.  The system then assumed that no other task could interrupt the current task while it was non-preemptive.  Since SIMPL+ would timeslice out and release the processor, if another SIMPL+ task performed a file operation, possible data corruption could occur. Redesign The goal of the redesign was to allow SIMPL+ to be able to run in a preemptive mode while still maintaining its logic wave propagation as well as protect against runaway user code.  The initial timeslice for SIMPL+ code will execute at a priority higher than the logic processor for code generated from events and the function Main().  This allows the signals to propagate as a logic wave.  If the SIMPL+ code either returns control back to the operating system (delay() or ProcessLogic()) or its 20 ms timeslice expires, the SIMPL+ task will then drop to the lowest priority in the system to protect against runaway SIMPL+ code.  It should be noted that Wait() events always run at the lowest priority.  There is no logic wave propagation requirement for Wait() events. The new design resolves the possible conflicts with the low-level constructs of the system that was causing problems during file operations.  Since there was no alternative to correcting these conflicts, we needed to make the SIMPL+ tasks preemptive.   Now that the SIMPL+ code starts at a higher priority than logic, there is the possibility that SIMPL programs will operate differently.  Most notable will be SIMPL+ events fired from SIMPL+ code running at the low priority.   This could be a Wait() statement or any SIMPL+ code after it has called ProcessLogic().  For example, if a Wait()  statement set a digital output high and that signal went to trigger other SIMPL+ code, the new SIMPL+ code would run before the rest of the Wait() statement.  This will create subtle timing changes that should be negligible for most applications.    Example The following is an example of SIMPL+ code that demonstrates a timing change caused by the new algorithm.   /\* Comments:   This is a test to demonstate what happens when a Wait() statement             triggers an input in the same module.  The premise behind the             module is that a device can only process commands one at a time.               The SIMPL program must wait until it either gets a response             from the device or a timeout occurs.               In this example program, there is no device attached to the com             port so the timeout will always occur.  It is the timeout code in             the Wait() statement that is causing the change that is seen in             firmware 3.137.  This modules emulates talking to two devices.  The             code for both devices is almost identical with the exception that             device 2 code has a ProcessLogic() call before its Wait() statement.             This reverts the scheduling to the old method. \*/ #DEFINE_CONSTANT    MAX_NUM_RETRIES    4 #DEFINE_CONSTANT    TIMEOUT_VALUE     100        // use a 1 second timeout #DEFAULT_NONVOLATILE #ENABLE_STACK_CHECKING DIGITAL_INPUT diEnable1;        // start sending commands. DIGITAL_INPUT diTrigger1;       // Resend the last command or get the next one. DIGITAL_INPUT diEnable2;        // start sending commands. DIGITAL_INPUT diTrigger2;       // Resend the last command or get the next one. STRING_INPUT siRx1$[1024];      // Holds the response from the first device. BUFFER_INPUT biCmdQueue1[1024]; // Commands to send to the first device. STRING_INPUT siRx2$[1024];      // Holds the response from the second device. BUFFER_INPUT biCmdQueue2[1024]; // Commands to send to the second device. DIGITAL_OUTPUT doResend1;       // this will be wrapped around to diTrigger1 DIGITAL_OUTPUT doResend2;       // this will be wrapped around to diTrigger2 DIGITAL_OUTPUT doTest1Complete; // For thistest only, clears the Enable input DIGITAL_OUTPUT doTest2Complete; STRING_OUTPUT soTx1$;           // Data to send to device 1. STRING_OUTPUT soTx2$;           // Data to send to device 2. //  Global Variables INTEGER   iCmdSendCnt1, iCmdSendCnt2;  // Retry counters STRING    sCmd1[80], sCmd2[80];        // holds the last command sent INTEGER_Function ExtractCommand1() {     if (Find("\n", biCmdQueue1) \> 0)     {     sCmd1 = Remove("\n", biCmdQueue1);     if (len(sCmd1) \> 0)     {             iCmdSendCnt1 = 0;             return (1);         }     }     else  // Queue is empty.  Test is over.  This is used for our test only.     {         doTest1Complete = 1;         doTest1Complete = 0;     }     return (0); } Function SendCommand1() {     /\* The Wait() statement pulses the Resend signal.  This will cause an PUSH        event to be generated.  In firmware version 3.137 and above, the PUSH        event runs before the code in the Wait() statement finished.  Since the        trigger event calls this routine again, the Wait() statement will not        get scheduled because it is still running in a different thread.        \*/     soTx1$ = sCmd1;     iCmdSendCnt1 = iCmdSendCnt1 + 1;     wait(TIMEOUT_VALUE, ResponseTimeout1)     {         doResend1 = 1;         doResend1 = 0;     }     } INTEGER_Function ExtractCommand2() {     if (Find("\n", biCmdQueue2) \> 0)     {     sCmd2 = Remove("\n", biCmdQueue2);     if (len(sCmd2) \> 0)     {             iCmdSendCnt2 = 0;             return (1);         }     }     else  // Queue is empty.  Test is over.  This is used for our test only.     {         doTest2Complete = 1;         doTest2Complete = 0;     }     return (0); } Function SendCommand2() {     /\* The Wait() statement pulses the Resend signal.  This will cause an PUSH        event to be generated.  In firmware version 3.137 and above, the PUSH        event runs before the code in the Wait() statement finished.  By calling        ProcessLogic(), the PUSH event task is scheduled at the same priority of        the Wait() event task and will run after the Wait() event has finished.        This allows the PUSH event task to schedule a new Wait() timeout for the        new command sent.      \*/     soTx2$ = sCmd2;     iCmdSendCnt2 = iCmdSendCnt2 + 1;     ProcessLogic();     wait(TIMEOUT_VALUE, ResponseTimeout2)     {         doResend2 = 1;         doResend2 = 0;     }     } //  Event Handlers PUSH diEnable1 {     if (ExtractCommand1() = 1)         SendCommand1(); } PUSH diEnable2 {     if (ExtractCommand2() = 1)         SendCommand2(); } /\* These RELEASE events are added to rerun the test.  Clear the buffers because    the queue will be reprimed when the test ends  \*/ RELEASE diEnable1 {     ClearBuffer(biCmdQueue1); } RELEASE diEnable2 {     ClearBuffer(biCmdQueue2); } PUSH diTrigger1 { if (iCmdSendCnt1 \>= MAX_NUM_RETRIES)  // get the next command {     if (ExtractCommand1() = 1)     {             SendCommand1();         }     }     else     {         SendCommand1();     } } PUSH diTrigger2 { if (iCmdSendCnt2 \>= MAX_NUM_RETRIES)  // get the next command {     if (ExtractCommand2() = 1)     {             SendCommand2();         }     }     else     {         SendCommand2();     } } CHANGE biCmdQueue1 {     if (diEnable1)     {         SendCommand1();     } } CHANGE biCmdQueue2 {     if (diEnable2)     {         SendCommand2();     } } CHANGE siRx1$ {     CancelWait(ResponseTimeout1);     // get next command     if (ExtractCommand1() = 1)         SendCommand1(); } CHANGE siRx2$ {     CancelWait(ResponseTimeout2);     // get next command     if (ExtractCommand2() = 1)         SendCommand2(); } Function Main() {     iCmdSendCnt1 = 0;     iCmdSendCnt2 = 0; } Glossary Preemptive – A process that will be interrupted when a higher priority process is ready to execute. Non-preemptive – A process that will continue to run even though a higher priority process is waiting to execute.   Timeslice –  A period of time that a process is allowed to execute before relinquishing the processor for other processes. [Task Switching for 2-Series Control Systems]: Task_Switching_for_2-Series_Control_Systems.md [Task Switching for X-Generation (CNX) Control Systems]: Task_Switching_for_CNX_Control_Systems.md -------------------------------------------------------------------------------- ## Task Switching > Task Switching for 2-Series Control Systems > Task Switching for 2-Series Control Systems -------------------------------------------------------------------------------- # Task Switching for 2-Series Control Systems In the 2-Series Control Systems, each SIMPL+ module also runs as one or more concurrent tasks in the control system. The MAIN and each event handler run as separate tasks sharing a common global data space. NOTE: the following applies to 2-series firmware prior to release 3.137. For information about release 3.137 and higher, refer to [Task Scheduling Changes and Consequences] NOTE: Also refer to [Task Switching for X-Generation (CNX) Control Systems] for a discussion of task switching in that environment. To insure that no SIMPL+ program takes too much time, each task is allotted a certain amount of time to run. If the task exceeds this time limit, the system will switch out and allow other tasks (including the SIMPL program) to run. It should also be noted that the task would run until it has completed the operation, the allotted time expires or a task switching call is executed. Unlike the X-Generation systems, the system will arbitrarily switch out at any point in time. If this may result in undesirable behavior, then the programmer should control his task switching by issuing a PROCESSLOGIC function. The system will perform a task switch when a PROCESSLOGIC or DELAY function is encountered. The PULSE will no longer cause a task switch because it is no longer needed for the logic processor to process the digital output pulse. Note that a WAIT does not cause a task switch but will execute in its own task. All outputs are processed by the logic processor as soon as assigned. As soon as the SIMPL+ module releases the processor, all the outputs are seen by the logic processor. Also, the programmer can read back DIGITAL_OUTPUTS and ANALOG_OUTPUTS without having to insert a PROCESSLOGIC in between.   To use the example from the Task Switching for X-Generation Control System discussion:     DIGITAL_INPUT trig;     ANALOG_OUTPUT i;     ANALOG_OUTPUT NewNumber;     INTEGER j;     PUSH trig     {       j=0;       NewNumber = 1234;       j = NewNumber; //j = 1234, not old value of NewNumber       FOR(j=0 to 32000)       {         i = j;       }     } A SIMPL program drives the trig signal and monitors the state of ANALOG_OUTPUT with an ANALOG DEBUGGER (Speedkey: TEST2) symbol. The TEST2 output would show all numbers from 0 to 32000. If it were critical that the ANALOG_OUTPUT were only updated with the final value, the following alternative solution could be used:     DIGITAL_INPUT trig;     ANALOG_OUTPUT i;     INTEGER j, q;     PUSH trig     {       j=0;       FOR(j=0 to 32000)       {         q = j;       }       i = q;     } This program output would only show the final result; the TEST2 would be triggered once with the value 32000. The system will still perform whatever task switching required. As with the X-Generation series, re-entrancy can still be a problem. When an event has task switched away, the event may be retriggered and a new copy of the event will start running. Therefore, SIMPL+ events are considered to be re-entrant. The amount of times that this could occur is dependent upon the available memory in the system. In order to prevent the event from running multiple times, refer to the re-entrant example in the X-Generation task switching section. The programmer should exercise caution when using looping constructs without constraints (i.e. while(1) ) or depend upon outside influence. Because each event will run for the allotted time unless specified otherwise, PROCESSLOGIC calls should be used to reduce the CPU overhead. Consider the following:     DIGITAL_INPUT diInput1, diInput2;     INTEGER I, LastNumSeconds;     PUSH diInput1     {       WHILE (diInput1)       {          // do something       }     }     main()     {     LastNumSeconds = 0;        WHILE (1)        {          seconds = GetSecondsNum();          IF (seconds \<\> LastNumSeconds)          {             // do something          }        }     } At the loop in MAIN, the programmer wants to perform an operation every second. This code will achieve that goal. However, a side effect of the code is that every time the task is scheduled to run, it will sit in a very tight loop checking for a change in the number of seconds. Since the allotted time for a SIMPL+ task to run is in fractions of a second, it is very unlikely to change during the allotted time. Unless the programmer puts in a DELAY which will put the task to "sleep" for a period of time, this task will dominate the CPU time. The programmer who writes the MAIN() function should also be aware that the MAIN() function begins running when the SIMPL program is initializing. The module's inputs do not have this programmed state until sometime after the first break in the program execution due either to a process logic statement, delay, or expiration of a time slice. The PUSH event indicates a more subtle problem. The programmer wants to loop in the event until the input diInput1 is released. Once the task containing the event is started, it will run for its allotted time and no other inputs will change. If the signal attached to the diInput1 signal goes low, the event will not see the change until the event switches out and the diInput1 low signal is processed.   The following is an alternative:     DIGITAL_INPUT diInput1, diInput2;     INTEGER I, LastNumSeconds;     PUSH diInput1     {       WHILE (diInput1)       {          // do something          ProcessLogic();       }     }     MAIN()     {     LastNumSeconds = 0;        WHILE (1)        {          seconds = GetSecondsNum();          IF (seconds \<\> LastNumSeconds)          {             // do something          }          delay(10);        }     } Here, a 100ms delay is put in the MAIN loop. That means that the task will only wake up 10-times per second. It will still catch the change of the seconds to within a 1/10 of a second and lessen system requirements.   The PROCESSLOGIC call in the PUSH event handler will immediately cause a task switch to be performed. This will allow a low transition on the diInput1 signal to be seen immediately, making the system more responsive. One more operational difference between the X-Generation and 2-Series control systems is the event interaction. For example: DIGITAL_INPUT diEvent1, diEvent2; PUSH diEvent1     {        PRINT("Starting Event 1\n");        DELAY(500); // 5 sec delay        PRINT ("Event 1 done\n");     } PUSH diEvent2     {        PRINT ("Starting Event 2\n");        DELAY (1500); // 15 sec delay        PRINT ("Event 2 done\n");     } The output from the X-Generation system would be: Starting Event 1 Starting Event 2 Event 2 Done Event 1 Done The order dictates that the second delay (15 seconds) will hold off the first delay. As soon as the second delay has finished, the first delay is checked. Therefore, the two events complete at approximately the same time (15 seconds). The output from the 2-Series system would be: Starting Event 1 Starting Event 2 Event 1 Done Event 2 Done The events run independently. When the 5-seconds expires for the first delay, the first event continues and prints its message. The second delay expires 10 seconds later and the message is displayed. [Task Scheduling Changes and Consequences]: Task_Scheduling_Changes_and_Consequences.md [Task Switching for X-Generation (CNX) Control Systems]: Task_Switching_for_CNX_Control_Systems.md -------------------------------------------------------------------------------- ## Task Switching > Task Switching for CNX Control Systems > Task Switching for X-Generation (CNX) Control Systems -------------------------------------------------------------------------------- # Task Switching for X-Generation (CNX) Control Systems Each SIMPL+ module runs as a separate task in the X-Generation (CEN-TVAV, CNMSX-AV/PRO, CNRACKX/-DP) Control System. In order to insure that no SIMPL+ program takes up too much time, each task is allotted a certain amount of time to run. If the task exceeds this time limit, the system will switch out and allow other tasks (including the SIMPL program) to run. The system will not arbitrarily switch out at any point in time. Even if the task limit is exceeded, the system will force a task switch only at predetermined points. The system will perform a task switch when a PROCESSLOGIC, DELAY, or PULSE function is encountered. When a task switch is performed, the output I/O definitions are updated (refer to ANALOG_OUTPUT, DIGITAL_OUTPUT, STRING_OUTPUT for further information). Note that a WAIT does not cause a task switch. When a WHILE, DO-UNTIL, or FOR construct encounters its last statement, or any construct that causes a "backwards branch", the system checks to see if a timeout has occurred. If the timeout has occurred, then the system will task switch away. When the module is given time to run, it will resume at the top of the construct. For this reason, a designer of a SIMPL+ module should take care to design with this in mind. A particular concern is if the outputs need to be updated in a specific fashion and have a loop, which may potentially cause the system to switch away. One solution would be to store the output variables in intermediate arrays or variables, and assign the intermediate variables to the output variables before the event terminates. For example:     DIGITAL_INPUT trig;     ANALOG_OUTPUT i;     INTEGER j;     PUSH trig     {       j=0;       FOR(j=0 to 32000)       {         i = j;       }     } A SIMPL program drives the trig signal and monitors the state of the analog_output with an ANALOG DEBUGGER (Speedkey: TEST2) symbol. If the system did not task switch out, the only TEST2 output would show 32000. If this program were run, there would be many outputs, indicating each time the FOR loop exceeded the allotted time, the SIMPL program would be given time to run and the TEST2 symbol would post the results.  If it were critical that the analog_output were only updated with the final value, the following alternative solution could be used:     DIGITAL_INPUT trig;     ANALOG_OUTPUT i;     INTEGER j, q;     PUSH trig     {       j=0;       FOR(j=0 to 32000)       {         q = j;       }       i = q;     } This program output would only show the final result; the TEST2 would be triggered once with the value 32000. The system will still perform whatever task switching it requires. When an event has task switched away, it is possible that the event may be retriggered and a new copy of the event will start running. Therefore, SIMPL+ events are considered to be re-entrant. The event may be reentered only a limited number of times before an Rstack overflow error occurs (refer to "Common Runtime Errors" that begins on page 128). In order to prevent the event from running multiple times, consider the following example:     DIGITAL_INPUT trig;     INTEGER I;     PUSH trig     {       FOR(I = 0 TO 32000)       {         // code       }     } This code will task switch away at some point in the FOR loop. If trig is hit again while the event is task switched out, a new copy will run. This code can be changed to prevent multiple copies from running.     DIGITAL_INPUT trig;     INTEGER I, Running;     PUSH trig     {       IF(!Running)       {         Running = 1;         FOR(I = 0 TO 32000)         {            // code         }         Running = 0;       }     }     FUNCTION MAIN()     {        Running = 0;     } In this case, a new variable, Running is declared and set to 0 on system startup in the MAIN. When the event is triggered, if Running is 0, then it will be set to 1, and the FOR loop will execute. Assume now the event has a task switch. If trig is hit again, the event will start, but will immediately exit because IF statement evaluates to false. When the task resumes, and ultimately completes, Running will be set to 0 again so the bulk of the function may execute again. NOTE:  The event is STILL reentering. It is being forced to terminate immediately and prevent reentry more than one level deep. -------------------------------------------------------------------------------- ## What's New > New Additions > Converting from an X-Generation to a 2-Series Target -------------------------------------------------------------------------------- # Converting from an X-Generation to a 2-Series Target - Select 2-Series Target within SIMPL+ environment (From the SIMPL+ application menu, select Build | 2-Series Control System Target.  X-Generation Target may be deselected if no longer needed). - Recompile the SIMPL+ program. -------------------------------------------------------------------------------- ## What's New > SIMPL Plus Revisions > SIMPL+ Revisions -------------------------------------------------------------------------------- # SIMPL+ Revisions For the latest revision information, refer to the Release Notes installed with SIMPL. This is accessed in the Start Menu under Programs|Crestron|SIMPL -------------------------------------------------------------------------------- ## What's New > X-Generation Target and 2-Series Target Differences -------------------------------------------------------------------------------- # X-Generation Target and 2-Series Target Differences - I/O Datatypes (DIGITAL_INPUT, etc) can no longer be passed to functions as arguments - Global variables can no longer be declared within User or Crestron Libraries - If TerminateEvent resides within a Wait Statement Block, it will only exit the Wait Statement Block’s function scope - NOT the PUSH, CHANGE, RELEASE or EVENT that it resides in - The following functions are no longer available in the 2-Series Control System: GetCIP() SetCIP() GetCresnet() SetCresnet() GetSlot() SetSlot() _OEM functions #ANALOG_INPUT_JOIN #ANALOG_OUTPUT_JOIN #DIGITAL_INPUT_JOIN #DIGITAL_OUTPUT_JOIN #STRING_INPUT_JOIN #STRING_OUTPUT_JOIN