Debugging
Spire_Jeff
Posts: 1,917
A question came up about debugging in a different thread and I feel that it needs it's own thread. The question was one about the effectiveness of the debugger and how it should be used. I am not sure about the Programmer I class, but debugging was only briefly touched in Programming II. Here is how I use some of the debugging tools and I look forward to other thoughts or suggestions on debugging.
First I use breakpoints to see how the program flows in certain areas. If I have a new function or call that doesn't seem to be doing what I want, I'll put a break at the top of the function and wait to see if the function even gets called. One thing that I have found is the netlinx program is sort of picky about where a break is placed. It doesn't break if the break is placed on a blank line above the code that executes (which makes sense). Next, I'll add the affected variables to the watch list so that as I step through, I can see what is going on. Sometimes I have to add some temporary variables just to make it easier to do this.
I then push a button (or whatever is needed) to trigger the code block to execute. If I don't see a break happen, I figure out what I screwed up in the logic that calls the function. If a break occurs where I want it, I will use the Single Step option to step through the code in question and then try to find out where the program and my thought process differ. If I get to the end of the block of code and feel I need another step through it, I hit the RUN button... sometimes I have to hit the run button a few times to get the program going again for some reason but it eventually gets running again. Then I just repeat the process until I figure out what I did wrong.
The other debug tool I use more and more is the device notification feature. This diagnostic tool let's you see what is being sent/received by all devices. This has helped me tremendously in figuring out what is happening with a few RS232 devices. It also helps me catch those times when I forget to do and ITOA() in a string that is being sent.
Lastly, I occasionally use the emulate a device to send strings to the processor to test out those odd bits of code that are there for either error handling or rarely used events. Such as to report a hardware failure or maybe a lamp burned out or ... just to test out the code without having to constantly break $500 projector bulbs
I am sure there are debugging features that I haven't even discovered yet so I am eagerly awaiting any other advice some of the more experienced programmers can offer.
Jeff
First I use breakpoints to see how the program flows in certain areas. If I have a new function or call that doesn't seem to be doing what I want, I'll put a break at the top of the function and wait to see if the function even gets called. One thing that I have found is the netlinx program is sort of picky about where a break is placed. It doesn't break if the break is placed on a blank line above the code that executes (which makes sense). Next, I'll add the affected variables to the watch list so that as I step through, I can see what is going on. Sometimes I have to add some temporary variables just to make it easier to do this.
I then push a button (or whatever is needed) to trigger the code block to execute. If I don't see a break happen, I figure out what I screwed up in the logic that calls the function. If a break occurs where I want it, I will use the Single Step option to step through the code in question and then try to find out where the program and my thought process differ. If I get to the end of the block of code and feel I need another step through it, I hit the RUN button... sometimes I have to hit the run button a few times to get the program going again for some reason but it eventually gets running again. Then I just repeat the process until I figure out what I did wrong.
The other debug tool I use more and more is the device notification feature. This diagnostic tool let's you see what is being sent/received by all devices. This has helped me tremendously in figuring out what is happening with a few RS232 devices. It also helps me catch those times when I forget to do and ITOA() in a string that is being sent.
Lastly, I occasionally use the emulate a device to send strings to the processor to test out those odd bits of code that are there for either error handling or rarely used events. Such as to report a hardware failure or maybe a lamp burned out or ... just to test out the code without having to constantly break $500 projector bulbs
I am sure there are debugging features that I haven't even discovered yet so I am eagerly awaiting any other advice some of the more experienced programmers can offer.
Jeff
0
Comments
SWITCH(X)
{
CASE 1:
{
//BLAH BLAH CODE CODE
SEND_STRING 0, "'CASE 1 TRIPPED ON SWITCH(X)'"
}
CASE 2:
{
//BLAH BLAH CODE CODE
SEND_STRING 0 ,"'CASE 2 TRIPPED ON SWITCH(X)'"
}
DEFAULT:
{
SEND_STRING 0 ,"'SWITCH(X) DEFAULTED X=',ITOA(X)"
}
}
This always help me get little bugs taken care of. That way you can know what the case is tripped, and if it isn't what the vaule of x was when it defaulted.
Note: to see these messages either enable NetLinx Diagnostics or telnet into the master and type MSG ON.
Have fun!
DEFINE_VARAIBLE
INTEGER nAudioDebug = 1
INTEGER nVIdeoDebug = 1
PUSH[someDevice,someAudioFunctionButton]
{
PUSH:
{
IF(nAudioDebug) SEND_STRING 0,'blah,blah,blah'
}
}
PUSH[someDevice,someVideoFunctionButton]
{
PUSH:
{
IF(nVideoDebug) SEND_STRING 0,'blah,blah,blah'
}
}
Syslog can do any of the following:
1. Log console messages conditionally (you can change how things are logged via the debugger) via SEND_STRING 0,
2. Log syslog messages (to a syslog server) conditionally. Syslog servers are installed on all UNIX systems, and decent freebie syslog servers are available for Windows (kiwi for one),
3. Make use of a "Flight Recorder". If your program crashes the NetLinx master (yeah, I've been there), then SEND_STRING 0 won't work anymore because those messages aren't sent instantly, and the NetLinx master may crash before you get those.
Messages logged can be rated "Emergency", "Alert Immediate", "Critical", "Warning", "Notice", "Info", and "Debug". You can tell syslog, on the fly, to log debug messages and higher, or just warnings and higher, etc. Messages generally have a "component" associated with it, and each component has separate settings for how it logs to syslog.
Here's a link if anyone's interested:
http://cvs.sourceforge.net/viewcvs.py/netlinx-modules/NetLinx-Modules/SyslogMod/
All my modules use it. If you don't want it, just pass 0:0:0 on to the module for the syslog port, and it's disabled. So the "cost" is one parameter to the module (if you don't want it), but a tremendously valuable tool if you do want it.
//#define MODULE_DEBUG_L1
#define MODULE_DEBUG_L2
PUSH[someDevice,someAudioFunctionButton]
{
PUSH:
{
#if_defined MODULE_DEBUG_L1
Log('blah,blah,blah');
#end_if
}
}
where Log is a function that calls SYSLOG. The advantage of syslog is that you can have the log on another machine, with a trace... The disadvantage is that during the NetLinx boot(DEFINE_START), you're piling tons of messages and that can crash the master...
The advantage of variables is that you can change them dynamically, but you bear the cost of evaluation. #define forces you to recompile for a change, but then for the useful life of the program (normally much longer than its "being-debugged" life) you do not have the performance hit.
With all that, the debugger is very rarely used...
Fred
But the primary tools I use are watch variables and SEND_STRING 0. I put a conditional in, as icraigie suggests, so the notifications aren't continually clogging the message stream. Between those two tools I can nearly always find any issues that creep up. Debug mode on an Axcent3 was kind of flaky, and tended to slow the entire system to a crawl, but in NetLinx it's much more robust. With it up I can watch key values and in conjunction with the SEND_STRING 0 messages telling me where in code I am, and what event have just occured, I can then see what key values are. i might add, I tend to use a lot of tracking variables to determine what state components of the system are in, and debug mode is most useful for making sure those are updating correctly. Variables that change frequently and quickly you pretty much have to output on a SEND_STRING or you will miss crucial changes.