0x6d61726b / mbed-os-retarget-segger-rtt

Dependents:   3_Test_AFE 1_Test_Flash_ADC_RTT

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