Friday, December 29, 2017

DO-178B/C Friendly Debugging Macros

Sorting through some PDFs and a PDF I had saved if from a friend, Mike Potts,, that is worth talking about.

In DO178B/C code, you want each line of code covered by a requirement or requirements, and ideally nothing else. The requirements say what you are going to do and only what you are going to do. Every DO178 project I have been in has had to deal with dead or deactivated code. There are many cases where you would like to keep some debugging code in there that you could re-activate when things go wrong to see information. Mike has a set of C macros that leave no code behind when compiled for production. Not even stray semi-colons.

I have used this philosophy many times over the years and keep a set of notes he gave me long ago about how to use this:


Ed asked about debug printf.

Here is how it works, you enable Serial-Input-Output (SERIO) Debugging Prints with #define SERIO_DEBUG.

To issue a debugged printf, you call it with two parentheses and NO semicolon.

Yes it looks weird, and takes some getting use to, but watch.

SERIO_DEBUG_MSG(("NMEA Semap, BUSY %11d\n", hi_pri_clock_read()/TICKS_PER_MS_HIGH))

A bunch of these macros are stored in the debugging module's header file:

#if (defined(SERIO_DEBUG))
#define SERIO_DEBUG_MSG(macro_string) printf macro_string;
#define SERIO_DEBUG_MSG(macro_string)

If SERIO_DEBUG is defined, then the SERIO_DEBUG_MSG and the first set of parentheses turn into a printf and a semicolon.

If SERIO_DEBUG is not defined, the while macro disappears (and does not even leave a semicolon behind).

This is kinda nice, not even a semicolon left behind to disturb certification. I like pre-processor tricks.
If you want to carry this idea forward, you can use something similar to:

#ifdef LINK_ERROR #include <debug.h>
#define GPS_ERROR_MSG(macro_string) {debug_msg macro_string; debugbreak();}
#define GPS_ERROR_MSG(macro_string) debug_msg macro_string;

This error printf happens to be writen as non-maskable, but can optionally issue a debugger break statement that is provided by a specific tool set.

We were consistent with this naming convention.

Enables were always *_DEBUG, and the associated debugging prints were always *_DEBUG_MSG.
This allowed us the option of sprinkling some extra computation code (within #ifdef *_DEBUG) near the printfs and still 'clearly' be debugging code.

These was also a master debug_on macro to globally enable the whole group.


Mike is a really sharp guy and always goes that the extra distance to make things right. One of his recent project's was to put together a really excellent setup guide for the Ubiquity EdgeRouter X, a fantastic little router. His setup guide was mentioned on Security Now, Episode 641, before Christmas and can be found at