Network Debug Console

Download DC Lib and PC Application source here

New: Download the Softools Version here.

Note: Softools users will need to download the DC version also if they need the source to the PC app.

Update: 9-26-2004: UDPDebug Version 1.2b

Fixed GPF error when loading Structures
Added dump memory to file option.

Update: 7-12-2004: UDPDebug Version 1.2a

The structure parser was a pain. I don't want to write a full 'C' preprocessor. This is limited, but I decided to add some more features:

  1. The parser now handles simple expressions in defines and array sizes. It can now handle things like char array[MAX_SIZE+1]. Operators supported are: +, -, /, * and ().
  2. Includes are supported from the current directory. #include <file.h> is ignored, but #include "file.h"
  3. A Log window that shows number of symbols, structure warnings.
  4. A new window has been added to display all of the #defines read.
  5. Menus have been re-arranged a bit.
  6. Improved syntax handling of defines and structures.

Update 12-4-2003: UDPDebug Version 1.1

Added wrap at column 80 option.
Fixed some watch problems.
Added "stop STDIO" function - will cause STDIO widow to ignore output.

Update 11-6-2003:

Added support for the softools compiler.

Update 5/11/2003:

Fixed minor bug where function local variable addresses were not decoded correctly.
Lib fixes for dbg_getchar(); typo left it undefined.

Update: 4/10/2003

The debugger has been updated to include the Bios symbols. Two new commands are now in the "File" menu: "Read Bios Symbols" and "Read Last Bios Symbols". This can be used to read the rabbitbios.map file normally found in c:\program files\rabbit\bios directory. The Bios symbols are merged with the symbols from the progam map file. This is useful for things like freq_divider and the I/O port shadow registers.

The watch window now supports Internal and Extrernal I/O data. Note this is only supported by the lib dated 4/10/2003 or later. The add or edit watch dialog now has radio buttons to select memory, Internal I/O or External I/O.

Hex addresses now must be entered as 0xnnnn or 0xnn:nnnn. The old method tried to guess, but a variable called abcd would be seen as hex as it has valid hex digits.

Notes on the debugger: 4/3/2003

The debugger and remote console used UDP for communication. UDP has low overhead and is relatively simple. It is not considered reliable. Rather than
add overhead of message acknowledges and retries, this limitation is accepted.

The PC console application will normally be much faster than the rabbit board. So only rarely will data be lost. The goal here is not to slow down the target. The PC application does retry messages for things like viewing data. The stdio console uses no retries/acks. This allows the PC console to be killed and the rabbit board to continue on at full speed.

Watch data will detect if data is missed. It will display "No response from target." A refresh will normally correct the situation.

How the stdio console is done:

The library has several routines that are similar to the stdio functions:

int dbg_printf(...) - same as printf but outputs to network console
int dbg_kbhit() - kbhit() equivalent
int dbg_getchar() - getchar() equivalent

You may use these functions in your code. They will output to the rabbit
stdio functions when the console is not connected.

If you would like to use the standard I/O function you can make the
following defines after the #use udpdebug.lib line:

#define printf dbg_printf
#define putchar(c) dbg_printf("%c",c)
#define kbhit dbg_kbhit
#define getchar dbg_getchar
#define puts(x) dbg_printf("%s",x)

The PC console sends a "connect" packet the the rabbit board. This tells the library where to send the stdio data. Every minute or so, the console also sends a "ping" to the rabbit board. This will reconnect if the board was reset.

The rabbit board then routes any stdio data to the console as a UDP packet. Similarly, the console sends keyboard keys to th rabbit. The library adds the characters to the input queue.

The stdio window has "time" and "log" icons to time-stamp messages and log output to a file.

Data display:

This was the main reason for writing the debug console. The DC IDE can not display structures. If you enter a structure name in the watch window it just displays "struct name", useless. You can add a watch for an item within a structure, but to display the entire structure, you have to add each item within the struct manually.

Another limitation is pointers. Suppose you have something like:

struct xxxx {.....};

struct xxx * cur_xxx;

It would be nice to be able to watch *cur_xxx. The debugger can do this. It reads the pointer at cur_xxx and then displays the structure. Even if the pointer changes, the debugger will display the correct data.

The way DC implements watch variables is stupid. A lot of code is dedicated to these watch variables within the rabbit code.

The debug console does it differently. The library implements a simple memory read and write command. Since the console itself knows the addresses, size and structure of the data, it can use the generic read/write command to display the data.

Structures and symbol definitions:

The console has the ability to parse source files for structures, #defines and enums. Parsing ".h" files would be easy. But DC uses everything in the ".c" file. So, it requires a little help.

You may define structures in 2 ways:

1. Use a separate file with the defines, structures etc.
2. Place all the definitions at the beginning of your program and then add a "#define NO_DEBUG_PARSE" statement. The debugger will stop processing input when it sees this define. The debugger can't handle regular 'c' code.

Version 1.2 adds an equation parser so you can define things like:

#define BUF_SIZE 64
#define MAX_MSG ((BUF_SIZE-4)/2)

Note: sizeof() is not supported

So a stucture can contain:

struct mystruct {
 int cmd;
 int param;
 int data[MAX_MSG];
};

Display Format Comments:

You can include keywords on structure entries. These are as follows:

HEX - show in hex
BINARY - show as binary
CHAR - show as char instead of int.
FUNC - show as pointer to function.

Example:

struct mystruct {
 int flags; // BINARY show as 0101010010 etc.
 long lval; // HEX
}

#Includes: (Softools only)

The structure include now will parse include files. This is intentionally limited. The parser can only handle structure definitions , defines and enums. Function prototypes are not supported. So, including the SofTools headers would cause errors. Also an include path would have to be implemented (not difficult.)

To allow UDPDebug to read all your #includes, each include file should be formatted as follows:

1. Things UDPDebug can understand
2. #define NO_DEBUG_PARSE
3. rest of file

So before #define NO_DEBUG_PARSE you could use:

struct {};
typedef
#define
#include <..> or "..." (<...> would be ignored.
enum

Note: The parser will add a define:

#define UDP_DEBUG_FLAG 1

So, your source can use: #ifdef UDP_DEBUG_FLAG to have areas that only apply to the debugger.

Symbol addresses:

The debug console will read the .map file for the symbol addresses. This is generated automatically by the compiler.

Adding the library to your code:

The sample "debugtest.c" shows how to use the library. Basically the steps are as
follows:

1. add udpdebug.lib to your lib.dir (DC only)
2. define network parameters. I.e. ip address, buffers etc normally. Be sure
to allow an extra UDP buffer and socket for the library.
3. Add a "#use udpdebug.lib" to your source after the #use dcrtcp.lib line.
(softools #include "udpdebug.h" and add the lib to project.)
4. In main call dbg_init(0) as the first function (prevents i/o problems.)
5. After sock_init() add a call to dbg_init(1) to enable the library.
6. In your main loop, add a call to debug_tick() to allow processing of debug messages.

Then either use the debug calls for stdio or remap the rabbit stdio calls to the debugger as shown in the "how the stdio console is done" section.

Running the debugger:

Run the UDPDebug.exe utility. It will ask for the rabbit board IP address. Once the address is entered, you should see a "STDIO connect from IP x.x.x.x port nnnn". This is from the rabbit board. Now any stdio will be routed through the console.

Displaying data:

Once the stdio console has connected to a rabbit board, any global or static variable can be displayed. This requires the console to know two things:

1. The symbol table.
2. The structure, #defines and enums.

The symbol table can be read via the "Read symbols" command from the File menu. This will read the .map file generated by your project.

The structures and defines are read by the "Load Structures" command from the File Menu. This can read a .c, .h or a .str file. If your program has no structures, then this is not needed.

Once the symbols and structures are loaded, you can then open a watch window. This is done via the "W" icon in the or the "New Watch Window" in the View menu.

There are two shortcuts in the file menu to read the last symbol and struct files used.

The "Add" icon can be used to add watch variables. This displays a dialog that specifies the address and type.

You can specify:

Simple type: int, char, float, long etc.
structures - pick name from list.
arrays - can be arrays of simple types or structures.
options - signed, unsigned, show as hex.
memory type - Memory, Internal I/O, External I/O

The address field can be in the following format:

1. a hex address (physical address) as 0xnn:nnnn or 0xnnnn
2. a symbol name.
3. can use +nnn or -nnn to add a hex offset to the address
4. can use *address to read a pointer and display the data at that address.
5. For function local variables (static) use function:variable (these should show up in the symbol list.)

watch lists can be saved and re-loaded later.

Using the sample:

compile and run the sample program debugtest.c

The run the debug console and enter the IP. It should respond with a "STDIO connect from x.x.x.x port nnnn" (your IP and the port used by the debugger.) You should then see "count is now nnn" mesages.

Load the symbols from the debugtest.map file.

Load the structures from the debugtest.c file.

Open a new watch window. Then use the file open icon to load demo.watch.

You should see the demo structure and the global variable 'counter'

The 'U' icon will update the display. Or, click on the "Auto" icon to set the time the data is updated.

If you right-click on a variable you can edit it. Try it with the demo.edit_me variable. You can also select it and click on the "Edit" icon.

The MOD icon can be used to edit the display format and type.

Notes/hints:

1. the debug console does not requre any debug support compiled in (i.e. include debug rst or enable single-step or watch variables.)
2. I use variables to enable debug features. I.e create global variable called 'verbose'. main() sets it to 0. When non-0 then extra printf()'s are used. I then can set this variable via the console to turn this on/off.
3. add the debug_tick() to a costate. If your program gets stuck in a loop elsewhere, the debugger may get unresponsive.
4. there is a generic memory display command. It can dump in hex/ascii any address.

Limitations:

Adding/removing watch entries still has problems. The display may get confused if a watch is deleted. This causes the program to crash. It works, but there seems
to be a specific sequence of add/edit/remove that blows up.

The future:

I dislike the DC IDE. I m tempeted to add full debugging to the console. Writing a disassembler would be straightforward. Source display would be hardest as DC has no documemtation on the line # information embedded in their files.

Writing a serial loader would be a bit or work. Using the network downloader would nice. It could call the RFU. It would call the command-line version of the DC compiler.

I have written a full debugger for an embedded 80186. This has register windows, structures, memory display, stop/start/single-step and full source or mixed asm/source display. I have a lot of code to pull from.

Right now, it is just a console and data display. A full IDE would be a lot of work. I am looking into this. I may release two versions, as is and the full IDE.

This is what the "eval" is about. To get good feedback from users as to where to go with this. Send any feedback to rabbit@shdesigns.org

The files are compressed into debug.zip.

Return to the file list: UDPDebug Files