Debugging Source Code Files

NetLinx Studio contains several useful options for debugging your Master Controller and Source Code files.

NOTE: The Debugging feature allows you to view variables declared within the scope of a Function and/or Call procedure. However, stack and parameter values are not editable. If you attempt to edit either the stack or parameter values, a warning message is displayed.

In order to begin debugging, your computer must be connected to a Master Controller, and you must have a compiled Source Code file active.

    • To use debugging, the Build With Source option must be selected in the NetLinx Compiler tab of the Preferences dialog before the file is compiled.
    • You cannot compile, send/receive files, or change port settings while the program is in debug mode.
    • Avoid declaring variables as volatile whenever possible, since volatile variables will not display their contents during the debug session.
    • NetLinx character strings by default are displayed in current length mode, while all other strings (including Integer strings) are displayed in total length mode.

Master Controller Debug Options

The Watch Bar is displayed when Start Debugging is selected from the Debug menu, or via the Debug Watch toolbar (FIG. 198).

FIG. 198 Watch Bar

The Watch Bar is a dockable window that allows you to view and edit the contents of variables within a compiled program. Also, you can control the execution through each pass of the mainline of a compiled program. Once Start Debugging has been selected, additional options in the Debug menu become available:

Start/Stop Debugging:

Ability to toggle the debug state of the application. There is no limitation on then number of NetLinx variables that can be watched in the Debug Watch Bars.

Single Step: Execute one line of a source code file at a time for a NetLinx Master.

The following options only apply to NetLinx code:

Run: To continue execution after a Single Step operation or from a toggled break point.

Run To Cursor: Execute the program and break on the line of code where the cursor is residing on the screen. Break: Stop execution of the program and highlight the line of code on the screen.

Edit Breakpoints: A dialog appears listing all the break points within the code.

Toggle Break Point:

Toggle a break point on the screen where the cursor is residing.

A red diamond appears next to the line of code to signify a break point.

Clear Break Points: Clears all the break points within the source code file.

Entering and Exiting Debug Mode

  1. Open and compile a Source Code file (that contains at least one variable), if you have not already done so. The file must be successfully compiled before you can enter debug mode.
  2. Choose Debug > Start Debugging to open the Watch Bar (FIG. 198 on page 111).

If this option is disabled, make sure your Master Communications Port settings are set to connect to your Master Controller. See the Connecting to a Master Controller section on page 118 for details.

  1. Right-click inside the Watch Bar to open the Watch Bar context menu.
  2. Click Add to insert a new variable in the Watch Bar. A box appears in the window, with a cursor blinking in the Name column.
  3. Type the syntax of the variable exactly as it is defined in the code and press the Enter key. The value of the specified variable appears next to the variable (in the Value column).
  4. You can select different view formats for the Value by right-clicking on the line containing the variable/value, and clicking on Display in the Watch Bar context menu. This opens the Display sub-menu, containing the following view options:

ASCII Display displays the value of the watched variable in ASCII format. Decimal Display displays the value of the watched variable in decimal format. Hexadecimal Display displays the value of the watched variable in hexadecimal format. Octal Display displays the value of the watched variable in octal format.

Binary Display displays the value of the watched variable in binary format.

To exit Debug mode, select Debug > Stop Debugging. or close the Watch Bar.

Using Single-Step Mode

In Single-step mode, program execution is suspended between each pass through mainline, allowing you to test programs one line at a time. In NetLinx systems, Single-step mode executes a single instruction in the source file.

To use Single-Step mode:

  1. Right-click on a watched variable and choose Debug > Single Step to put the Master into single-step mode.
  2. With the watched variable selected, select Debug > Single Step. This command executes mainline one time and breaks.

NOTE: In NetLinx, you can use breakpoints with single-step mode. When the breakpoint is encountered (and the program is suspended), you can single-step without a watched variable reference.

Changing the Value of a Watched Variable

Once you have entered Debug mode, you can change the name and/or value of any watched variable, via the Value column in the Watch Bar:

  1. Select a watched variable in the Watch Bar.
  2. To change the variable's value, double-click on the desired variable's value to change the value to an edit field, which you can modify as desired.

Debug Mode Error Messages

The most common warnings that you may get when entering Debug Mode (Debug > Start Debugging) are:

  1. No Debug Information:

FIG. 199 No Debug information

The source code file was not compiled with debug information - this can usually be ignored if you're only watching variables, but if you're getting weird behavior, recompile with Compile with Debug Info enabled (in the NetLinx Compiler tab of the Preference dialog).

You will always need debug symbols for breakpoint debugging.

  1. File no longer matches:

FIG. 200 File no longer matches

If you've made any changes to the source file, including a re-save, you'll get a message similar to the one above. It can often be safely ignored, but select No if you've done any significant editing.

  1. Missing files.

Using Current Length with Total Length Disabled

The way you initialize variables in your source code affects the use of Current Length. For example, if you have a variable declared as:

CHAR cat[3]

in debug, Total Length = 3 and Current Length = 0.

If you modified the code as:

CHAR cat[3] = 'CAT'

in debug Total Length = 3 and Current Length = 3.

If you modified the code like this:

CHAR cat[3]

and then in the DEFINE_START section of your code you added:

cat[1] = 'C'

cat[2] = 'A'

cat[3] = 'T'

in debug Total Length = 3 and Current Length = 0, because setting values using array indexing does not set the current length.

Using Breakpoints

NetLinx systems allow you to use Breakpoints to execute a single instruction in the source file. You can set a breakpoint on any line of code (other than a comment) that is within the DEFINE_PROGRAM section.

The following is an example of a SEND_LEVEL breakpoint:

PUSH[dvLocalTP3,1] PUSH[dvLocalTP3,2]

{

fTestLevel=fTestLevel + 1; SEND_LEVEL dvLocalTP3,1,fTestLevel;

}

Note that semicolons are used in the example to terminate each line in a breakpoint. The only time that the semicolon is absolutely necessary is when a breakpoint is set at the last line of code. To keep things simple, consider terminating each breakpoint with a semicolon.

Setting a Breakpoint

  1. Place the cursor on a line of code in the DEFINE_PROGRAM section (other than a comment).
  2. To insert the breakpoint at the cursor position, right-click to open the Editor window context menu, and select Toggle Breakpoint, or use the Toggle Breakpoint toolbar button.
  3. A red arrow appears in the Editor window, to the left of the cursor position.
    • A green bar highlighting the line of code, and the execution arrow (a little green arrow) indicate the current execution point.
    • To execute the next line of code, right-click and choose Step Into. You'll see the execution pointer advance one line.
    • If you no longer need to single step, right-click and choose Run.

NOTE: If you are not currently debugging, you won't see execution break until you start debugging (Debug > Start Debugging).

Clearing Breakpoints

To clear an individual breakpoint, or clear all breakpoints in a file:

    • To clear an individual breakpoint - Place the cursor on a line of code containing a set breakpoint, and choose Debug > Toggle Breakpoint, or use the Toggle Breakpoint toolbar button to unset the breakpoint on that line.
    • To clear all breakpoints in a f ile - Choose Debug > Clear All Breakpoints, or use the Clear All Breakpoints toolbar button.

Editing Breakpoints

Select Debug > Edit Breakpoints to access the Breakpoints dialog. Use the options in this dialog to toggle any breakpoints set in the active (NetLinx) Source Code file (FIG. 201).

FIG. 201 Breakpoints dialog

Troubleshooting Debugging

NetLinx Debugger Not Stopping On a Breakpoint

Symptoms - A breakpoint is set on a line of code, but the code does not stop execution on this line. The line of code in question contains a SEND_COMMAND, SEND_STRING, or SEND_LEVEL.

Cause - The debugger will not stop on a line of code that sends a command, string, or level because of a device declared as an integer instead of a DEVICE:PORT:SYSTEM (D:P:S) structure.

Example:

DEFINE_DEVICE VCR = 2

TP = 128 DEFINE_EVENT BUTTON_EVENT[TP,101]

{ PUSH:

{

SEND_COMMAND VCR," 'SP', 9" //The debugger will not stop if you put a breakpoint here

}

}

Resolution - Declare devices using the full D:P:S structure. In fact, you should always do this in NetLinx. Example:

DEFINE_DEVICE VCR = 2:1:0

TP = 128:1:0 DEFINE_EVENT BUTTON_EVENT[TP,101]

{ PUSH:

{

SEND_COMMAND VCR," 'SP', 9" //The debugger will now stop if you put a breakpoint here

}

}

NetLinx Master Error - DEVICE_ID Error

When calling DEVICE_ID, this run time error can occur:

CIpLibrary::DEVICE_ID - Error 1

This error is cause by passing a parameter that is not of type DEV to the DEVICE_ID keyword. This usually occurs when converting code to NetLinx. To fix this error, try the following:

    • Look for all references to the DEVICE_ID function
    • Make sure the value passed to the function is of type DEV. If this appears inside a DEFINE_CALL or DEFINE_FUNCTION

and a parameter is passed to the DEVICE_ID function, make sure that parameter is of type DEV.

Debugging NetLinx Code with Terminal or Telnet Messages

This is often referred to as using "SEND_STRING 0's" in your code. Strings sent to device 0 (the master), port 1 or port 0, system 0 (the local system) will show up in a terminal or Telnet session once the programmer has entered 'MSG ON'<enter> at the prompt.

For example, if this line is in your code:

SEND_STRING 0,'some message'

your terminal will display something like:

(0100636312) some message

when the code executes.

The 13 characters to the left of the message are called the "time stamp" or "tic time". Also, by default, the master will append a carriage return and line feed to the end of each string.

If the master is v2.10.81 or higher, there are additional MSG ON modes:

  1. All messages with tic time. This is the same as 'MSG ON' with no type.
  2. SEND_STRING 0 only (no tic time in front of string and no CR and LF appended).
  3. SEND_STRING 0 with tic time pre-pended to string. Example:

MSG ON 2<enter>

sets the message mode to 2. To turn off these messages type 'MSG OFF'<enter>.

The SEND_STRING 0 message is obviously completely customizable - whatever is typed in will be what you are going to get.

This can be used as a way to see the value of variables at specific points in the code, by sending that information from that point, instead of stopping execution with a breakpoint. This is especially useful if programmers have to watch non-printable data bytes that only show as blank boxes in Windows programs, the SEND_STRING 0 code can reformat the data as a string of printable ASCII characters.

The 'debug.axi' file (attached to Technote #461) contains 16 subroutines useful for this type of debugging and other purposes, e.g. DPS_TO_STRING and STRING_TO_DEV are useful for passing DEV information between masters via a virtual device in a master-to- master scenario. Theses subroutines were created as an AXI so programmers could use a single #INCLUDE at the top of the program rather than having to dig through the old programs and find the appropriate code to cut and paste.

  1. FUNCTION CHAR[17] DEV_TO_STRING (DEV dvDEV)

Formatting NetLinx device structures as strings take a little more than the simple ITOA(<device>) that was done in . This function takes a DEV and returns a string in the '<number>:<port>:<system>' format.

  1. FUNCTION CHAR[25] DEVCHAN_TO_STRING (DEVCHAN dcDC)

This function returns a DEVCHAN as a string with brackets in the format '[<number>:<port>:<system>,<chan>]'.

  1. FUNCTION CHAR[25] DEV_CHAN_TO_STRING (DEV dvDEV, INTEGER nChannel) Same as DEVCHAN_TO_STRING but takes a separate DEV and INTEGER as parameters. Returns '[<number>:<port>:<system>,<chan>]'.
  2. FUNCTION CHAR[25] DEVLEV_TO_STRING (DEVLEV dlDL)

This function returns a DEVLEV as a string in the format '<number>:<port>:<system>,<lev>'.

  1. FUNCTION CHAR[25] DEV_LEV_TO_STRING (DEV dvDEV, INTEGER nLevel) Same as DEVLEV_TO_STRING but takes a separate DEV and INTEGER as parameters. Returns '<number>:<port>:<system>,<lev>'.
  2. FUNCTION CHAR[17] DPS_TO_STRING (DEV dvDEV)

This function takes a DEV and returns a string in the '<number>:<port>:<system>' format. Same as DEV_TO_STRING

except it always returns the actual system number, not system 0, if the device is so defined.

  1. CALL 'SEND 131 BYTE PACKETS TO MASTER' (sSTRING[])

Strings sent to the master will be truncated if they are longer than 131 bytes. This call breaks the strings up if they are longer than 131 bytes. Otherwise, it does not modify the string.

Use with master v2.10.81 or higher "MSG ON 2" mode to see only the data in the sSTRING.

  1. CALL 'SEND 7BIT ASCII TO DEBUG' (dvDEBUG,STR1[],STR2[],nLine,nMode)

This call is similar to 'SEND ASCII TO MASTER' but with a little more flexibility: dvDEBUG is the destination device for the string. It could be the local master, a virtual device on the local system (see TN435), an IP device, serial device, etc.…

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. Data bytes < $20 (ASCII control codes) and > $7E (~) are formatted as hex and separated by commas. Note that a space ($20) is not added between STR1 and STR2.
    • nLine is the line length. This may need to be changed if a terminal with a line length other than the typical 80 characters is being used. If not, just leave it as 0 for the defaults.

If nMode is 2, nLine defaults to 80, else nLine defaults to 67 to allow 13 characters for the tic time.

    • nMode is the mode, if "MSG ON 2" mode is being used to set it to 2; otherwise, use 0 for the defaults.
  • CALL 'SEND ASCII TO DEBUG' (dvDEBUG,STR1[],STR2[],nLine,nMode)

This call is similar to 'SEND ASCII TO MASTER' but with a little more flexibility: dvDEBUG is the destination device for the string. It could be the local master, a virtual device on the local system (see TN435), an IP device, serial device, etc.…

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. Data bytes < $20 (ASCII control codes) and $7F (DEL) are formatted as hex and separated by commas. Note that a space ($20) is not added between STR1 and STR2.
    • nLine is the line length. This may need to be changed if a terminal with a line length other than the typical 80 characters is being used. If not, just leave it as 0 for the defaults.

If nMode is 2, nLine defaults to 80, else nLine defaults to 67 to allow 13 characters for the tic time.

    • nMode is the mode, if "MSG ON 2" mode is being used to set it to 2; otherwise, use 0 for the defaults.
  • CALL 'SEND ASCII TO MASTER' (STR1[],STR2[])

SEND_STRING 0's are formatted into 67 character lines. Since the tic time sent with MSG ON mode 1(default) and mode 3 prepend 13 characters to the string, each line fills the typical 80 character line (67 + 183 = 80).

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. Data bytes < $20 (ASCII control codes) and $7F (DEL) are formatted as hex and separated by commas. Note that a space ($20) is not added between STR1 and STR2.
  • CALL 'SEND DECIMAL TO DEBUG' (dvDEBUG,STR1[],STR2[],nLine,nMode)

dvDEBUG is the destination device for the string. It could be the local master, a virtual device on the local system (see TN435), an IP device, serial device, etc.…

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. All data bytes are formatted as 3 digit decimal and separated by commas. Note that a space ($20) is not added between STR1 and STR2.
    • nLine is the line length. This may need to be changed if a terminal with a line length other than the typical 80 characters is being used. If not, just leave it as 0 for the defaults.

If nMode is 2, nLine defaults to 80, else nLine defaults to 67 to allow 13 characters for the tic time.

nMode is the mode, if "MSG ON 2" mode is being used to set it to 2; otherwise, use 0 for the defaults.

  1. CALL 'SEND DEVICE_INFO TO DEBUG' (dvDEBUG,dvDEV)
    • dvDEBUG is the destination device for the strings. It could be the local master, a virtual device on the local system (see

TN435), an IP device, serial device, etc.…

    • dvDEV is the device from which to get the info.
  • CALL 'SEND DECIMAL TO DEBUG' (dvDEBUG,STR1[],STR2[],nLine,nMode)

    • dvDEBUG is the destination device for the string. It could be the local master, a virtual device on the local system (see

TN435), an IP device, serial device, etc.…

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. All data bytes are formatted as 3 digit decimal and separated by commas. Note that a space ($20) is not added between STR1 and STR2.
    • nLine is the line length. This may need to be changed if a terminal with a line length other than the typical 80 characters is being used. If not, just leave it as 0 for the defaults.

If nMode is 2, nLine defaults to 80, else nLine defaults to 67 to allow 13 characters for the tic time.

    • nMode is the mode, if "MSG ON 2" mode is being used to set it to 2; otherwise, use 0 for the defaults.
  • CALL 'SEND INTEGER TO DEBUG' (dvDEBUG,STR1[],STR2[],nLine,nMode)

    • dvDEBUG is the destination device for the string. It could be the local master, a virtual device on the local system (see

TN435), an IP device, serial device, etc.…

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. Data bytes are not formatted. Note that a space ($20) is not added between STR1 and STR2.
    • nLine is the line length. This may need to be changed if a terminal with a line length other than the typical 80 characters is being used. If not, just leave it as 0 for the defaults.

If nMode is 2, nLine defaults to 80, else nLine defaults to 67 to allow 13 characters for the tic time.

    • nMode is the mode, if "MSG ON 2" mode is being used to set it to 2; otherwise, use 0 for the defaults.
  • CALL 'SEND ITOHEX TO MASTER' (STR1[],STR2[])

SEND_STRING 0's are formatted into 67 character lines. Since the tic time sent with MSG ON mode 81(default) and mode 3 prepends 13 characters to the string, each line fills the typical 80 character line (67 + 13 = 80).

    • STR1 is a header sent with each line - this is a good place to use DEV_TO_STRING.
    • STR2 is data. All data bytes are formatted as hex and separated by commas. Note that a space ($20) is not added between

STR1 and STR2.

  1. CALL 'STRING TO DEV' (Txt[], dvDEV)

Takes ASCII string Txt[] of the form '<dev>' or '<dev>:<port>:<sys>' and stores this as a DEV. The dev data in Txt[] can be embedded in other non-numeric characters. If Txt[] does not contain any numerals, dvDEV will default to 0:1:0 (the local master). In order to use these subroutines, debug.axi must be in the compile path. It is suggested that an "AXIs" folder in the My Documents folder be created, save debug.axi there, then add that path to NetLinx Studio "Edit/Preferences/NetLinx Compiler Options/Include Files". Then add the line: #INCLUDE 'debug.axi' to the source code.

"Debug.axi" and example code are attached to Tech Note #461. To access AMX Tech Notes, go to www.amx.com, log in as a dealer and go to Tech Center > Tech Notes.

results matching ""

    No results matching ""