Lesson 005: Redirecting printf to UART Part 2

Lesson 004’s printf redirection seemed to work well, until you tried using format specifiers (IE: printf(“%d”, 5);

When you tried running this code, you end up with the same problem as when we originally used printf.

Instead of intercepting lower level function calls, this time we’ll create our own printf function. Fortunately, the source code for printf is aviliable as open source and is located at http://sourceware.org/git/?p=glibc.git;a=blob_plain;f=stdio-common/printf.c;hb=3321010338384ecdc6633a8b032bb0ed6aa9b19a.

int
__printf (const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vfprintf (stdout, format, arg);
  va_end (arg);

  return done;
}

We’ll take this definition, call it _printf (single underscore instead of two), replace vfprintf (where the formatting magic actually happens) and replace it with vsnprintf, and write the results from vsnprintf to UART.

/* HAL-only entry function */
#include "hal_data.h"

#include 
#include 
#include 

// Buffer Sizes
#define OUTPUT_BUFFER_SIZE 1024

// Output Buffer
char outputBuffer[OUTPUT_BUFFER_SIZE];

volatile bool transmitComplete;

// Custom printf prototype
int _printf (const char *format, ...);

// Custom printf Implementation
int _printf (const char *format, ...)
{
    // Temporary Buffer
   char buffer[OUTPUT_BUFFER_SIZE];

   // Variable Argument List
   va_list arg;

   int done;

   // Get Variable Arguments
   va_start (arg, format);

   // Pass format string and arguments to string formatter
   done = vsnprintf(buffer, OUTPUT_BUFFER_SIZE, format, arg);

   // Start Transmission
   transmitComplete = false;
   g_uart.p_api->write (g_uart.p_ctrl, buffer, done);

   while (!transmitComplete)
   {
   }

   // End Variable Arguments
   va_end (arg);

   return done;
}

// Callback Function for UART interrupts
void user_uart_callback(uart_callback_args_t * p_args)
{
    // Get Event Type
    switch (p_args->event)
    {
        // Transmission Complete
        case UART_EVENT_TX_COMPLETE:
            transmitComplete = true;
        break;

        defaut: break;
    }
}

void hal_entry(void)
{
    // Open UART
    g_uart.p_api->open (g_uart.p_ctrl, g_uart.p_cfg);

    // Use TTY100 commands to clear screen and reset screen pointer
    _printf("\033[2J"); // Clear Screen
    _printf("\033[H"); // Return Home
    _printf("\033[3J"); // Clear Back Buffer

    // Print Header
    _printf("Day Six - printf Redirection, Part 2\r\n");

    // Verify printf functions with format specifiers
    _printf("          String: %s\r\n", "This is a string");
    _printf("     Integer (5): %d\r\n", 5);
    _printf("Float (3.141592): %f\r\n", 3.141592);

    while (true)
    {
    }
}

Full source code is available on GitHub at https://github.com/lycannon/ajwrs/tree/master/DaySix

Advertisements

2 thoughts on “Lesson 005: Redirecting printf to UART Part 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s