RTT Debugger Library

Dependents:   BREAK_SENSOR_LED MPU9250_simple MPU9250_tap_better Sensor_tap_BLE ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SEGGER_RTT_printf.c Source File

SEGGER_RTT_printf.c

00001 /*********************************************************************
00002 *              SEGGER MICROCONTROLLER GmbH & Co. KG                  *
00003 *        Solutions for real time microcontroller applications        *
00004 **********************************************************************
00005 *                                                                    *
00006 *        (c) 2014-2014 SEGGER Microcontroller GmbH & Co. KG          *
00007 *                                                                    *
00008 *       Internet: www.segger.com Support: support@segger.com         *
00009 *                                                                    *
00010 **********************************************************************
00011 ----------------------------------------------------------------------
00012 File    : SEGGER_RTT_printf.c
00013 Date    : 17 Dec 2014
00014 Purpose : Replacement for printf to write formatted data via RTT
00015 ---------------------------END-OF-HEADER------------------------------
00016 */
00017 #include "SEGGER_RTT.h"
00018 #include "SEGGER_RTT_Conf.h"
00019 
00020 /*********************************************************************
00021 *
00022 *       Defines, configurable
00023 *
00024 **********************************************************************
00025 */
00026 
00027 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
00028   #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
00029 #endif
00030 
00031 #include <stdlib.h>
00032 #include <stdarg.h>
00033 
00034 
00035 #define FORMAT_FLAG_LEFT_JUSTIFY   (1 << 0)
00036 #define FORMAT_FLAG_PAD_ZERO       (1 << 1)
00037 #define FORMAT_FLAG_PRINT_SIGN     (1 << 2)
00038 #define FORMAT_FLAG_ALTERNATE      (1 << 3)
00039 
00040 /*********************************************************************
00041 *
00042 *       Types
00043 *
00044 **********************************************************************
00045 */
00046 
00047 typedef struct {
00048   char* pBuffer;
00049   int   BufferSize;
00050   int   Cnt;
00051 
00052   int   ReturnValue;
00053 
00054   unsigned RTTBufferIndex;
00055 } SEGGER_RTT_PRINTF_DESC;
00056 
00057 /*********************************************************************
00058 *
00059 *       Function prototypes
00060 *
00061 **********************************************************************
00062 */
00063 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
00064 
00065 /*********************************************************************
00066 *
00067 *       Static code
00068 *
00069 **********************************************************************
00070 */
00071 /*********************************************************************
00072 *
00073 *       _StoreChar
00074 */
00075 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
00076   int Cnt;
00077 
00078   Cnt = p->Cnt;
00079   if ((Cnt + 1) <= p->BufferSize) {
00080     *(p->pBuffer + Cnt) = c;
00081     p->Cnt = Cnt + 1;
00082     p->ReturnValue++;
00083   }
00084   //
00085   // Write part of string, when the buffer is full
00086   //
00087   if (p->Cnt == p->BufferSize) {
00088     if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
00089       p->ReturnValue = -1;
00090     } else {
00091       p->Cnt = 0;
00092     }
00093   }
00094 }
00095 
00096 /*********************************************************************
00097 *
00098 *       _PrintUnsigned
00099 */
00100 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, int NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
00101   static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00102   unsigned Div;
00103   unsigned Digit = 1;
00104   unsigned Number;
00105   unsigned Width;
00106   char c;
00107 
00108   Number = v;
00109 
00110   //
00111   // Get actual field width
00112   //
00113   Width = 1;
00114   while (Number >= Base) {
00115     Number = (Number / Base);
00116     Width++;
00117   }
00118   if ((unsigned)NumDigits > Width) {
00119     Width = NumDigits;
00120   }
00121   //
00122   // Print leading chars if necessary
00123   //
00124   if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) {
00125     if (FieldWidth != 0) {
00126       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0)) {
00127         c = '0';
00128       } else {
00129         c = ' ';
00130       }
00131       while ((FieldWidth != 0) && (Width < FieldWidth--)) {
00132         _StoreChar(pBufferDesc, c);
00133         if (pBufferDesc->ReturnValue < 0) {
00134           return;
00135         }
00136       }
00137     }
00138   }
00139   //
00140   // Count how many digits are required by precision
00141   //
00142   while (((v / Digit) >= Base) | (NumDigits-- > 1)) {
00143     Digit *= Base;
00144   }
00145   //
00146   // Output digits
00147   //
00148   do {
00149     Div = v / Digit;
00150     v -= Div * Digit;
00151     _StoreChar(pBufferDesc, _aV2C[Div]);
00152     if (pBufferDesc->ReturnValue < 0) {
00153       break;
00154     }
00155     Digit /= Base;
00156   } while (Digit);
00157   //
00158   // Print trailing spaces if necessary
00159   //
00160   if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
00161     if (FieldWidth != 0) {
00162       while ((FieldWidth != 0) && (Width < FieldWidth--)) {
00163         _StoreChar(pBufferDesc, ' ');
00164         if (pBufferDesc->ReturnValue < 0) {
00165           return;
00166         }
00167       }
00168     }
00169   }
00170 }
00171 
00172 /*********************************************************************
00173 *
00174 *       _PrintInt
00175 */
00176 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
00177   unsigned Width;
00178   unsigned Number;
00179 
00180   Number = (v < 0) ? -v : v;
00181 
00182   //
00183   // Get actual field width
00184   //
00185   Width = 1;
00186   while (Number >= Base) {
00187     Number = (Number / Base);
00188     Width++;
00189   }
00190   if (NumDigits > Width) {
00191     Width = NumDigits;
00192   }
00193   if ((FieldWidth > 0) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
00194     FieldWidth--;
00195   }
00196 
00197   //
00198   // Print leading spaces if necessary
00199   //
00200   if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0) || (NumDigits != 0)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0)) {
00201     if (FieldWidth != 0) {
00202       while ((FieldWidth != 0) && (Width < FieldWidth--)) {
00203         _StoreChar(pBufferDesc, ' ');
00204         if (pBufferDesc->ReturnValue < 0) {
00205           return;
00206         }
00207       }
00208     }
00209   }
00210   //
00211   // Print sign if necessary
00212   //
00213   if (v < 0) {
00214     v = -v;
00215     _StoreChar(pBufferDesc, '-');
00216     if (pBufferDesc->ReturnValue < 0) {
00217       return;
00218     }
00219   } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
00220     _StoreChar(pBufferDesc, '+');
00221     if (pBufferDesc->ReturnValue < 0) {
00222       return;
00223     }
00224   }
00225   //
00226   // Print leading zeros if necessary
00227   //
00228   if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) && (NumDigits == 0)) {
00229     if (FieldWidth != 0) {
00230       while ((FieldWidth != 0) && (Width < FieldWidth--)) {
00231         _StoreChar(pBufferDesc, '0');
00232         if (pBufferDesc->ReturnValue < 0) {
00233           return;
00234         }
00235       }
00236     }
00237   }
00238 
00239   //
00240   // Print number without sign
00241   //
00242   _PrintUnsigned(pBufferDesc, v, Base, NumDigits, FieldWidth, FormatFlags);
00243 }
00244 
00245 /*********************************************************************
00246 *
00247 *       Public code
00248 *
00249 **********************************************************************
00250 */
00251 /*********************************************************************
00252 *
00253 *       SEGGER_RTT_vprintf
00254 *
00255 *  Function description
00256 *    Stores a formatted string in SEGGER RTT control block.
00257 *    This data is read by the host.
00258 *
00259 *  Parameters
00260 *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
00261 *    sFormat      Pointer to format string
00262 *    pParamList   Pointer to the list of arguments for the format string
00263 *
00264 *  Return values
00265 *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
00266 *     < 0:  Error
00267 */
00268 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
00269   char c;
00270   SEGGER_RTT_PRINTF_DESC BufferDesc;
00271   int v;
00272   unsigned NumDigits;
00273   unsigned FormatFlags;
00274   unsigned FieldWidth;
00275   char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
00276 
00277   BufferDesc.pBuffer        = acBuffer;
00278   BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
00279   BufferDesc.Cnt            = 0;
00280   BufferDesc.RTTBufferIndex = BufferIndex;
00281   BufferDesc.ReturnValue    = 0;
00282 
00283   do {
00284     c = *sFormat++;
00285     if (c == 0) {
00286       break;
00287     }
00288     if (c == '%') {
00289       //
00290       // Filter out flags
00291       //
00292       FormatFlags = 0;
00293       do {
00294         c = *sFormat;
00295         switch (c) {
00296         case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
00297         case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
00298         case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
00299         case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
00300         default:  goto FilterFieldWidth;                   break;
00301         }
00302       } while (1);
00303       //
00304       // filter out field with
00305       //
00306 FilterFieldWidth:
00307       FieldWidth = 0;
00308       do {
00309         c = *sFormat;
00310         if (c < '0' || c > '9') {
00311           break;
00312         }
00313         sFormat++;
00314         FieldWidth = FieldWidth * 10 + (c - '0');
00315       } while (1);
00316 
00317       //
00318       // Filter out precision (number of digits to display)
00319       //
00320       NumDigits = 0;
00321       c = *sFormat;
00322       if (c == '.') {
00323         sFormat++;
00324         do {
00325           c = *sFormat;
00326           if (c < '0' || c > '9') {
00327             break;
00328           }
00329           sFormat++;
00330           NumDigits = NumDigits * 10 + (c - '0');
00331         } while (1);
00332       }
00333       //
00334       // Filter out length modifier
00335       //
00336       c = *sFormat;
00337       do {
00338         if (c == 'l' || c == 'h') {
00339           c = *sFormat++;
00340           continue;
00341         }
00342         break;
00343       } while (1);
00344       //
00345       // Handle specifiers
00346       //
00347       switch (c) {
00348       case 'c': {
00349         char c0;
00350         v = va_arg(*pParamList, int);
00351         c0 = (char)v;
00352         _StoreChar(&BufferDesc, c0);
00353         break;
00354       }
00355       case 'd':
00356         v = va_arg(*pParamList, int);
00357         _PrintInt(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
00358         break;
00359       case 'u':
00360         v = va_arg(*pParamList, int);
00361         _PrintUnsigned(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
00362         break;
00363       case 'x':
00364       case 'X':
00365         v = va_arg(*pParamList, int);
00366         _PrintUnsigned(&BufferDesc, v, 16, NumDigits, FieldWidth, FormatFlags);
00367         break;
00368       case 's':
00369         {
00370           const char * s = va_arg(*pParamList, const char *);
00371           do {
00372             c = *s++;
00373             if (c == 0) {
00374               break;
00375             }
00376            _StoreChar(&BufferDesc, c);
00377           } while (BufferDesc.ReturnValue >= 0);
00378         }
00379         break;
00380       case 'p':
00381         v = va_arg(*pParamList, int);
00382         _PrintUnsigned(&BufferDesc, v, 16, 8, 8, 0);
00383         break;
00384       case '%':
00385         _StoreChar(&BufferDesc, '%');
00386         break;
00387       }
00388       sFormat++;
00389     } else {
00390       _StoreChar(&BufferDesc, c);
00391     }
00392   } while (BufferDesc.ReturnValue >= 0);
00393 
00394   if (BufferDesc.ReturnValue > 0) {
00395     //
00396     // Write remaining data, if any
00397     //
00398     if (BufferDesc.Cnt != 0) {
00399       SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
00400     }
00401     BufferDesc.ReturnValue += BufferDesc.Cnt;
00402   }
00403   return BufferDesc.ReturnValue;
00404 }
00405 
00406 /*********************************************************************
00407 *
00408 *       SEGGER_RTT_printf
00409 *
00410 *  Function description
00411 *    Stores a formatted string in SEGGER RTT control block.
00412 *    This data is read by the host.
00413 *
00414 *  Parameters
00415 *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
00416 *    sFormat      Pointer to format string, followed by the arguments for conversion
00417 *
00418 *  Return values
00419 *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
00420 *     < 0:  Error
00421 *
00422 *  Notes
00423 *    (1) Conversion specifications have following syntax:
00424 *          %[flags][FieldWidth][.Precision]ConversionSpecifier
00425 *    (2) Supported flags:
00426 *          -: Left justify within the field width
00427 *          +: Always print sign extension for signed conversions
00428 *          0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
00429 *        Supported conversion specifiers:
00430 *          c: Print the argument as one char
00431 *          d: Print the argument as a signed integer
00432 *          u: Print the argument as an unsigned integer
00433 *          x: Print the argument as an hexadecimal integer
00434 *          s: Print the string pointed to by the argument
00435 *          p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
00436 */
00437 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
00438   va_list ParamList;
00439 
00440   va_start(ParamList, sFormat);
00441   return SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
00442 }
00443 /*************************** End of file ****************************/