Notes on the debugger:

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.

How the stdio console is done:

The library implements a stdio structure called: debug_stdio. You can use the file routines with
this handle or remap stdio to the debugger by assigning: _stdio = debug_stdio;

int debug_kbhit(void)	- returns non-0 if key is in the input buffer

int near debug_getchar(void) - returns next char or -1 if no chars are available.

void near debug_putchar(char c) - sends a char to the debugger.

Output is queued into a buffer. This buffer is sent when it is full or on the next debug_tick call.

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 debug_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 implemnts 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.

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 #include udpdebug.h to your source
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 the udpdebug.lib to your link list.
4. 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:

Note: varibales are shown in their map file format. These will normally have an "_" or "$" appended to
them. The debugger automatically remaps the RAM variables. It does this by checking if the physical
address is different than the logical address. RAM data normally has this attribute. It then add the
current value of STACKSEG to these addresses.

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.

The address field can be in the following format:

1. a hex address (physical address)
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 menory 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 structure definitions must be loaded once. Loading a new one may confuse the
watch list. The easiest solution is to save the watch window, close it, reload the
structures/symbols and then reload the watch list.

The future:

I dislike the DC IDE. I am 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. 

