Seger Real time terminal, use RTT viewer to view messages through the segger debugger instead of art

Fork of SEGGER_RTT by Glimworm Beacons

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 - 2016  SEGGER Microcontroller GmbH & Co. KG        *
00007 *                                                                    *
00008 *       www.segger.com     Support: support@segger.com               *
00009 *                                                                    *
00010 **********************************************************************
00011 *                                                                    *
00012 *       SEGGER RTT * Real Time Transfer for embedded targets         *
00013 *                                                                    *
00014 **********************************************************************
00015 *                                                                    *
00016 * All rights reserved.                                               *
00017 *                                                                    *
00018 * * This software may in its unmodified form be freely redistributed *
00019 *   in source form.                                                  *
00020 * * The source code may be modified, provided the source code        *
00021 *   retains the above copyright notice, this list of conditions and  *
00022 *   the following disclaimer.                                        *
00023 * * Modified versions of this software in source or linkable form    *
00024 *   may not be distributed without prior consent of SEGGER.          *
00025 * * This software may only be used for communication with SEGGER     *
00026 *   J-Link debug probes.                                             *
00027 *                                                                    *
00028 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
00029 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
00030 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
00031 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
00032 * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
00033 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
00034 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
00035 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
00036 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
00037 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
00038 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
00039 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
00040 * DAMAGE.                                                            *
00041 *                                                                    *
00042 **********************************************************************
00043 *                                                                    *
00044 *       RTT version: 5.12g                                           *
00045 *                                                                    *
00046 **********************************************************************
00047 ---------------------------END-OF-HEADER------------------------------
00048 File    : SEGGER_RTT_printf.c
00049 Purpose : Replacement for printf to write formatted data via RTT
00050 ----------------------------------------------------------------------
00051 */
00052 #include "SEGGER_RTT.h"
00053 #include "SEGGER_RTT_Conf.h"
00054 
00055 /*********************************************************************
00056 *
00057 *       Defines, configurable
00058 *
00059 **********************************************************************
00060 */
00061 
00062 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
00063   #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
00064 #endif
00065 
00066 #include <stdlib.h>
00067 #include <stdarg.h>
00068 
00069 
00070 #define FORMAT_FLAG_LEFT_JUSTIFY   (1u << 0)
00071 #define FORMAT_FLAG_PAD_ZERO       (1u << 1)
00072 #define FORMAT_FLAG_PRINT_SIGN     (1u << 2)
00073 #define FORMAT_FLAG_ALTERNATE      (1u << 3)
00074 
00075 /*********************************************************************
00076 *
00077 *       Types
00078 *
00079 **********************************************************************
00080 */
00081 
00082 typedef struct {
00083   char*     pBuffer;
00084   unsigned  BufferSize;
00085   unsigned  Cnt;
00086 
00087   int   ReturnValue;
00088 
00089   unsigned RTTBufferIndex;
00090 } SEGGER_RTT_PRINTF_DESC;
00091 
00092 /*********************************************************************
00093 *
00094 *       Function prototypes
00095 *
00096 **********************************************************************
00097 */
00098 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
00099 
00100 /*********************************************************************
00101 *
00102 *       Static code
00103 *
00104 **********************************************************************
00105 */
00106 /*********************************************************************
00107 *
00108 *       _StoreChar
00109 */
00110 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
00111   unsigned Cnt;
00112 
00113   Cnt = p->Cnt;
00114   if ((Cnt + 1u) <= p->BufferSize) {
00115     *(p->pBuffer + Cnt) = c;
00116     p->Cnt = Cnt + 1u;
00117     p->ReturnValue++;
00118   }
00119   //
00120   // Write part of string, when the buffer is full
00121   //
00122   if (p->Cnt == p->BufferSize) {
00123     if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
00124       p->ReturnValue = -1;
00125     } else {
00126       p->Cnt = 0u;
00127     }
00128   }
00129 }
00130 
00131 /*********************************************************************
00132 *
00133 *       _PrintUnsigned
00134 */
00135 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
00136   static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00137   unsigned Div;
00138   unsigned Digit;
00139   unsigned Number;
00140   unsigned Width;
00141   char c;
00142 
00143   Number = v;
00144   Digit = 1u;
00145   //
00146   // Get actual field width
00147   //
00148   Width = 1u;
00149   while (Number >= Base) {
00150     Number = (Number / Base);
00151     Width++;
00152   }
00153   if (NumDigits > Width) {
00154     Width = NumDigits;
00155   }
00156   //
00157   // Print leading chars if necessary
00158   //
00159   if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
00160     if (FieldWidth != 0u) {
00161       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
00162         c = '0';
00163       } else {
00164         c = ' ';
00165       }
00166       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
00167         FieldWidth--;
00168         _StoreChar(pBufferDesc, c);
00169         if (pBufferDesc->ReturnValue < 0) {
00170           break;
00171         }
00172       }
00173     }
00174   }
00175   if (pBufferDesc->ReturnValue >= 0) {
00176     //
00177     // Compute Digit.
00178     // Loop until Digit has the value of the highest digit required.
00179     // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
00180     //
00181     while (1) {
00182       if (NumDigits > 1u) {       // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
00183         NumDigits--;
00184       } else {
00185         Div = v / Digit;
00186         if (Div < Base) {        // Is our divider big enough to extract the highest digit from value? => Done
00187           break;
00188         }
00189       }
00190       Digit *= Base;
00191     }
00192     //
00193     // Output digits
00194     //
00195     do {
00196       Div = v / Digit;
00197       v -= Div * Digit;
00198       _StoreChar(pBufferDesc, _aV2C[Div]);
00199       if (pBufferDesc->ReturnValue < 0) {
00200         break;
00201       }
00202       Digit /= Base;
00203     } while (Digit);
00204     //
00205     // Print trailing spaces if necessary
00206     //
00207     if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
00208       if (FieldWidth != 0u) {
00209         while ((FieldWidth != 0u) && (Width < FieldWidth)) {
00210           FieldWidth--;
00211           _StoreChar(pBufferDesc, ' ');
00212           if (pBufferDesc->ReturnValue < 0) {
00213             break;
00214           }
00215         }
00216       }
00217     }
00218   }
00219 }
00220 
00221 /*********************************************************************
00222 *
00223 *       _PrintInt
00224 */
00225 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
00226   unsigned Width;
00227   int Number;
00228 
00229   Number = (v < 0) ? -v : v;
00230 
00231   //
00232   // Get actual field width
00233   //
00234   Width = 1u;
00235   while (Number >= (int)Base) {
00236     Number = (Number / (int)Base);
00237     Width++;
00238   }
00239   if (NumDigits > Width) {
00240     Width = NumDigits;
00241   }
00242   if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
00243     FieldWidth--;
00244   }
00245 
00246   //
00247   // Print leading spaces if necessary
00248   //
00249   if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
00250     if (FieldWidth != 0u) {
00251       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
00252         FieldWidth--;
00253         _StoreChar(pBufferDesc, ' ');
00254         if (pBufferDesc->ReturnValue < 0) {
00255           break;
00256         }
00257       }
00258     }
00259   }
00260   //
00261   // Print sign if necessary
00262   //
00263   if (pBufferDesc->ReturnValue >= 0) {
00264     if (v < 0) {
00265       v = -v;
00266       _StoreChar(pBufferDesc, '-');
00267     } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
00268       _StoreChar(pBufferDesc, '+');
00269     } else {
00270 
00271     }
00272     if (pBufferDesc->ReturnValue >= 0) {
00273       //
00274       // Print leading zeros if necessary
00275       //
00276       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
00277         if (FieldWidth != 0u) {
00278           while ((FieldWidth != 0u) && (Width < FieldWidth)) {
00279             FieldWidth--;
00280             _StoreChar(pBufferDesc, '0');
00281             if (pBufferDesc->ReturnValue < 0) {
00282               break;
00283             }
00284           }
00285         }
00286       }
00287       if (pBufferDesc->ReturnValue >= 0) {
00288         //
00289         // Print number without sign
00290         //
00291         _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
00292       }
00293     }
00294   }
00295 }
00296 
00297 /*********************************************************************
00298 *
00299 *       Public code
00300 *
00301 **********************************************************************
00302 */
00303 /*********************************************************************
00304 *
00305 *       SEGGER_RTT_vprintf
00306 *
00307 *  Function description
00308 *    Stores a formatted string in SEGGER RTT control block.
00309 *    This data is read by the host.
00310 *
00311 *  Parameters
00312 *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
00313 *    sFormat      Pointer to format string
00314 *    pParamList   Pointer to the list of arguments for the format string
00315 *
00316 *  Return values
00317 *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
00318 *     < 0:  Error
00319 */
00320 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
00321   char c;
00322   SEGGER_RTT_PRINTF_DESC BufferDesc;
00323   int v;
00324   unsigned NumDigits;
00325   unsigned FormatFlags;
00326   unsigned FieldWidth;
00327   char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
00328 
00329   BufferDesc.pBuffer        = acBuffer;
00330   BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
00331   BufferDesc.Cnt            = 0u;
00332   BufferDesc.RTTBufferIndex = BufferIndex;
00333   BufferDesc.ReturnValue    = 0;
00334 
00335   do {
00336     c = *sFormat;
00337     sFormat++;
00338     if (c == 0u) {
00339       break;
00340     }
00341     if (c == '%') {
00342       //
00343       // Filter out flags
00344       //
00345       FormatFlags = 0u;
00346       v = 1;
00347       do {
00348         c = *sFormat;
00349         switch (c) {
00350         case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
00351         case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
00352         case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
00353         case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
00354         default:  v = 0; break;
00355         }
00356       } while (v);
00357       //
00358       // filter out field with
00359       //
00360       FieldWidth = 0u;
00361       do {
00362         c = *sFormat;
00363         if ((c < '0') || (c > '9')) {
00364           break;
00365         }
00366         sFormat++;
00367         FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
00368       } while (1);
00369 
00370       //
00371       // Filter out precision (number of digits to display)
00372       //
00373       NumDigits = 0u;
00374       c = *sFormat;
00375       if (c == '.') {
00376         sFormat++;
00377         do {
00378           c = *sFormat;
00379           if ((c < '0') || (c > '9')) {
00380             break;
00381           }
00382           sFormat++;
00383           NumDigits = NumDigits * 10u + ((unsigned)c - '0');
00384         } while (1);
00385       }
00386       //
00387       // Filter out length modifier
00388       //
00389       c = *sFormat;
00390       do {
00391         if ((c == 'l') || (c == 'h')) {
00392           sFormat++;
00393           c = *sFormat;
00394         } else {
00395           break;
00396         }
00397       } while (1);
00398       //
00399       // Handle specifiers
00400       //
00401       switch (c) {
00402       case 'c': {
00403         char c0;
00404         v = va_arg(*pParamList, int);
00405         c0 = (char)v;
00406         _StoreChar(&BufferDesc, c0);
00407         break;
00408       }
00409       case 'd':
00410         v = va_arg(*pParamList, int);
00411         _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
00412         break;
00413       case 'u':
00414         v = va_arg(*pParamList, int);
00415         _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
00416         break;
00417       case 'x':
00418       case 'X':
00419         v = va_arg(*pParamList, int);
00420         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
00421         break;
00422       case 's':
00423         {
00424           const char * s = va_arg(*pParamList, const char *);
00425           do {
00426             c = *s;
00427             s++;
00428             if (c == '\0') {
00429               break;
00430             }
00431            _StoreChar(&BufferDesc, c);
00432           } while (BufferDesc.ReturnValue >= 0);
00433         }
00434         break;
00435       case 'p':
00436         v = va_arg(*pParamList, int);
00437         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
00438         break;
00439       case '%':
00440         _StoreChar(&BufferDesc, '%');
00441         break;
00442       default:
00443         break;
00444       }
00445       sFormat++;
00446     } else {
00447       _StoreChar(&BufferDesc, c);
00448     }
00449   } while (BufferDesc.ReturnValue >= 0);
00450 
00451   if (BufferDesc.ReturnValue > 0) {
00452     //
00453     // Write remaining data, if any
00454     //
00455     if (BufferDesc.Cnt != 0u) {
00456       SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
00457     }
00458     BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
00459   }
00460   return BufferDesc.ReturnValue;
00461 }
00462 
00463 /*********************************************************************
00464 *
00465 *       SEGGER_RTT_printf
00466 *
00467 *  Function description
00468 *    Stores a formatted string in SEGGER RTT control block.
00469 *    This data is read by the host.
00470 *
00471 *  Parameters
00472 *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
00473 *    sFormat      Pointer to format string, followed by the arguments for conversion
00474 *
00475 *  Return values
00476 *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
00477 *     < 0:  Error
00478 *
00479 *  Notes
00480 *    (1) Conversion specifications have following syntax:
00481 *          %[flags][FieldWidth][.Precision]ConversionSpecifier
00482 *    (2) Supported flags:
00483 *          -: Left justify within the field width
00484 *          +: Always print sign extension for signed conversions
00485 *          0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
00486 *        Supported conversion specifiers:
00487 *          c: Print the argument as one char
00488 *          d: Print the argument as a signed integer
00489 *          u: Print the argument as an unsigned integer
00490 *          x: Print the argument as an hexadecimal integer
00491 *          s: Print the string pointed to by the argument
00492 *          p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
00493 */
00494 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
00495   int r;
00496   va_list ParamList;
00497 
00498   va_start(ParamList, sFormat);
00499   r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
00500   va_end(ParamList);
00501   return r;
00502 }
00503 /*************************** End of file ****************************/