0

I have existing code with various debug messages. Our embedded system does not have an external connection for a terminal. I want to modify the printf so that its output goes to a memory location, rather than STDOUT, which is mapped to a FIFO. I guess I need to find write my own outbyte/outnum. Just cant seem to find the GNU code where I can grab things.

I am running a microblaze processor inside an Xilinx FPGA. All print statements are for debugging. We are running GNU tools (Xilinx SDK). For development, was able stick an UART in the design and wire the uart to a few test points.

As we get ready to deploy, I will no longer have this visibility. We do have a USB-to-Serial connecton, but it looks like a fifo, not a serial port to the embedded system. We have a protocol for sending messages over this link. I was thinking of adding a debug message to our protocol. I would like to redirect my print statement to a buffer, and then process this buffer.

I was trying to take the existing printf (xil_printf) and create my own cc_printf, by rewriting the outbyte code, but just not able to dig down in the code far enough to see how to do it. (Frankly, I am VHDL/hardware guy).

Overall code size is tens of thousands of lines of C code. My section is maybe 3-4 thousand lines of code. The basic operation is for software/hardware updates of the system to come in via the USB port and moved to FLASH memory. My code parses incoming packets coming over the USB-to-serial link. Basically there is a bit set that tells me that there is a packet ready in a receive buffer. I process the packet and write to FLASH. As part of the protocol, there are ACK/NACKs/ABorts. I currently use the printf to printout statuses to my lab bench version of the system.

As stated, I would like to embed these printouts into our protocol. I am not married to printf, and would use some other print-function. I would like to print out messages and data. If something else would be a better starting point, I am fine with that. It seems that the biggest issue for me is grabbing the output of the print and directing it where to go.

  • `fprintf`? `dprintf`? – Ruslan Osmanov Oct 31 '16 at 15:46
  • 1
    It doesn't make much sense to use stdio.h on embedded systems. You are probably better off using some generic UART printing routine. Your MCU likely comes with app notes that shows how to quickly whip together a UART driver. – Lundin Oct 31 '16 at 15:48
  • What kind and size of code (thousands of source code lines)? What embedded system target? How do you compile it? With what compiler? Please **edit your question** to improve & motivate it! – Basile Starynkevitch Oct 31 '16 at 15:58
  • 1
    Welcome to Stack Overflow. Please check out [the tour](http://stackoverflow.com/tour), and thoroughly read [the help pages](http://stackoverflow.com/help) - in particular, ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic), ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask), ["How do I ask a good question?"](http://stackoverflow.com/help/how-to-ask) and ["How to create a Minimal, Complete, and Verifiable example"](http://stackoverflow.com/help/mcve). – Random Davis Oct 31 '16 at 16:00
  • Even after the edit, we still have no idea about code size & purpose. – Basile Starynkevitch Oct 31 '16 at 16:44

2 Answers2

1

Don't use printf directly, for debugging purposes.

Use a macro, perhaps something like

#define DEBUGPRINTF(Fmt,...) do \
   {printf("%s:%d: " Fmt "\n", __FILE__, __LINE__,  __VA_ARGS__);} while(0)

Then, once you have converted all your debug printf (and only these) to DEBUGPRINTF you just need to change the definition of that macro (e.g. on the embedded system, perhaps using snprintf ...).

So in the rest of your code, replace a printf("debugging x=%d\n", x); with DEBUGPRINTF("debugging x=%d", x); but do that only for debugging prints. BTWK 4KLOC (for your part) is really tiny, and even 200KLOC (for the whole thing) is small enough to make that replacement doable "by hand" (e.g. Emacs "find & replace interactively").

(I am guessing that you are first developing a small piece of code -a few thousand lines- on your laptop, and later porting it to the embedded system)

Once you have converted all your debug printf to DEBUGPRINTF (and only the debugging prints!) you can redefine that macro, perhaps inspired by

#define DEBUGPRINTF(Fmt,...) do \
  {snprintf(debugbuffer, sizeof(debugbuffer), Fmt, __VA_ARGS__); } while(0)

(I guess that you'll need to add something more in that macro -probably before the closing brace- to actually send the debug output -that is the content of debugbuffer- somewhere, but how to do that is implementation & system specific)

But more likely you'll disable the debug printf with

#define DEBUGPRINTF(Fmt,...) do{}while(0)

BTW, the embedded target system might not even have any snprintf ...

If you want to study some readable C standard library implementation (on Linux) consider looking inside musl-libc source code. You'll need to understand what system calls are.

Actually, you should in fact write and debug your code on your laptop (e.g. running Linux) and only put on the embedded system something which you believe has no bugs. In practice, avoid deploying code with debug printfs (or think in advance of something much better). See also this.

It seems that the biggest issue for me is grabbing the output of the print and directing it where to go.

Probably use snprintf then "send" the debugbuffer to the appropriate place using appropriate primitives. With snprintf you know the size of the message (e.g. with the return value from snprintf and/or using %n in the format control string). Or have your own logging or debugging variadic function (using <stdarg.h> and va_start etc ....)

Do not confuse debugging messages with logging messages. If you want logging, design it carefully. But debugging messages should probably be removed at deployment time.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • It's probably good advice, but it doesn't actually answer the question; so the next person searching finds this question, and maybe this advice doesn't apply to his situation. Maybe good info for a comment instead of an answer imo – Mark Adelsberger Oct 31 '16 at 15:54
  • @MarkAdelsberger: That does not fit in a comment, and I have no idea (only guesses) about the OP code and target system. – Basile Starynkevitch Oct 31 '16 at 16:08
  • The essential info in the ORIGINAL answer (as it looked when I commented) would fit in a comment, actually. And regardless, it still doesn't answer the question asked; sorry if you disagree. – Mark Adelsberger Oct 31 '16 at 16:15
  • The question by OP is actually not precise enough to get any meaningful answer. I asked (in a comment for the question) the OP to edit his question to improve it, and he did not do that (yet). – Basile Starynkevitch Oct 31 '16 at 16:16
  • All the reasons in the world don't change the basic fact, that I don't believe your response answered the question asked. If you're saying you couldn't answer the question as asked, then my solution would be to not post something as an answer. Again, sorry if you don't agree. – Mark Adelsberger Oct 31 '16 at 16:19
  • Updated question with more detail. Note that the system has no OS or filesystem – Paul Gigliotti Oct 31 '16 at 16:36
  • @PaulGigliotti: We still don't know the size & purpose of your code. – Basile Starynkevitch Oct 31 '16 at 16:52
  • Debug messages does not mean bugs in the code. Lets say they are status messages, so that I can see what is happening in the system, should something come up. – Paul Gigliotti Oct 31 '16 at 17:46
  • Then it is called *logging* (or *log messages*) and should be designed as such. – Basile Starynkevitch Oct 31 '16 at 17:48
  • I added additional detail to the original question, with info on code size and function. – Paul Gigliotti Oct 31 '16 at 17:50
  • Ok, logging. It started as debug, and morphing into logging. Seemed that the easiest way forward was to modify the printfs, such that I could use that output for logging. – Paul Gigliotti Oct 31 '16 at 17:50
1

The Posix function fmemopen allows you to open a memory buffer like a file and returns a FILE * that can be used with the standard IO functions, like fprintf. As far as printing to a device that's not a serial port, I don't know what OS (of any) you are running on, but if present you could write a stream device driver for that custom device and set your stdout and stderr (and maybe stdin) to that. If you're running without an OS then somewhere someone has created a FILE structure that in interfacing with the serial port somehow, and printf is using that.

nategoose
  • 12,054
  • 27
  • 42