Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible write to console without stdlibs? c/c++

I am programming on an arm microprocessor and am trying to debug using print statements via UART. I do not want to add stdlibs just for debugging. Is there a way to print to the console without stdio.h/iostream.h ? Is it possible for me to write my own printf()?

Alternatively I can do this using a DMA controller and writing to the UART directly. However I would like to avoid that is possible. Using the built in test function "echo" or "remote loop-back" I know I have the UART configured properly.

like image 423
Sam Avatar asked May 08 '13 21:05

Sam


2 Answers

Since printing out information through a serial port in an embedded system modifies the main program's timing, the best solution I've found is to send a small message encoded in 2 bytes (sometimes 1 byte works fine), and then using a program in the PC to decode those messages and provide the necessary information, which can include statistics and everything you may need. This way, I'm adding just a little bit of overhead to the main program, and letting the PC do the hard work to process the messages. Maybe something like this:

  • 1 byte message: bits 7:4 = module ID, bits 3:0 = debug info.

  • 2 bytes message: bits 15:12 = module ID, bits 11:8 = debug info, bits 7:0 = data.

Then, in the PC software, you have to declare a table with the messages that map to a given module ID/debug info pair, and use them to be printed on the screen.

Maybe it's not as flexible as the pseudo-printf function, since you need a fixed set of messages in the PC to decode, but it doesn't add too much overhead, as I mentioned before.

Hope it helps.

Fernando

like image 82
Fernando Avatar answered Oct 28 '22 22:10

Fernando


Short answer: Yes, it's entirely possible to do both of your solutions.

The printf function is quite complex if you want to support all of the data types and formats. But it's not that hard to write something that can output a string or an integer in a few different bases (most people only need decimal and hex, but octal probably only adds another 3-4 lines of code once you have decimal and hex).

Typically, printf is written like this:

 int printf(const char *fmt, ...)
 {
     int ret;
     va_list args; 

     va_start(args, fmt)
     ret = do_xprintf(outputfunc, NULL, fmt, args); 
     va_end(args);
     return ret;
}

And then the do_xprintf() does all the hard work for all variants (printf, sprintf, fprintf, etc)

int do_xprintf(void (*outputfunc)(void *extra, char c), void *extra, const char *fmt, va_list args)
{
    char *ptr = fmt;
    while(1)
    {
       char c = *ptr++;

       if (c == '%')
       {
            c = *ptr++; // Get next character from format string. 
            switch(c)
            {
               case 's': 
                  char *str = va_arg(args, const char *);
                  while(*str)
                  {
                      count++;
                      outputfunc(extra, *str);
                      str++;
                  }
                  break; 
               case 'x': 
                  base = 16;
                  goto output_number;

               case 'd':
                  base = 10;
         output_number:
                  int i = va_arg(args, int);
                  // magical code to output 'i' in 'base'. 
                  break;

               default:
                  count++;
                  outputfunc(extra, c);
                  break;
         }
         else
             count++;
             outputfunc(extra, c);
     }
     return count;
 }                

Now, all you need to do is fill in a few bits of the above code and write an outputfunc() that outputs to your serial port.

Note that this is rough sketch, and I'm sure there are some bugs in the code - and if you want to support floating point or "widths", you will have to work a bit more at it...

(Note on the extra parameter - for output to a FILE * that would be the filepointer, for sprintf, you can pass a structure for the buffer and position in the buffer, or something like that)

like image 22
Mats Petersson Avatar answered Oct 28 '22 22:10

Mats Petersson