xref: /btstack/3rd-party/segger-rtt/SEGGER_RTT_printf.c (revision 779af47be2a26fca484358b6dbf3172ffb019f79)
17dc86dfdSMatthias Ringwald /*********************************************************************
2*779af47bSMatthias Ringwald *                    SEGGER Microcontroller GmbH                     *
37dc86dfdSMatthias Ringwald *       Solutions for real time microcontroller applications         *
47dc86dfdSMatthias Ringwald **********************************************************************
57dc86dfdSMatthias Ringwald *                                                                    *
6*779af47bSMatthias Ringwald *            (c) 1995 - 2018 SEGGER Microcontroller GmbH             *
77dc86dfdSMatthias Ringwald *                                                                    *
87dc86dfdSMatthias Ringwald *       www.segger.com     Support: [email protected]               *
97dc86dfdSMatthias Ringwald *                                                                    *
107dc86dfdSMatthias Ringwald **********************************************************************
117dc86dfdSMatthias Ringwald *                                                                    *
127dc86dfdSMatthias Ringwald *       SEGGER RTT * Real Time Transfer for embedded targets         *
137dc86dfdSMatthias Ringwald *                                                                    *
147dc86dfdSMatthias Ringwald **********************************************************************
157dc86dfdSMatthias Ringwald *                                                                    *
167dc86dfdSMatthias Ringwald * All rights reserved.                                               *
177dc86dfdSMatthias Ringwald *                                                                    *
187dc86dfdSMatthias Ringwald * SEGGER strongly recommends to not make any changes                 *
197dc86dfdSMatthias Ringwald * to or modify the source code of this software in order to stay     *
207dc86dfdSMatthias Ringwald * compatible with the RTT protocol and J-Link.                       *
217dc86dfdSMatthias Ringwald *                                                                    *
227dc86dfdSMatthias Ringwald * Redistribution and use in source and binary forms, with or         *
237dc86dfdSMatthias Ringwald * without modification, are permitted provided that the following    *
247dc86dfdSMatthias Ringwald * conditions are met:                                                *
257dc86dfdSMatthias Ringwald *                                                                    *
267dc86dfdSMatthias Ringwald * o Redistributions of source code must retain the above copyright   *
277dc86dfdSMatthias Ringwald *   notice, this list of conditions and the following disclaimer.    *
287dc86dfdSMatthias Ringwald *                                                                    *
297dc86dfdSMatthias Ringwald * o Redistributions in binary form must reproduce the above          *
307dc86dfdSMatthias Ringwald *   copyright notice, this list of conditions and the following      *
317dc86dfdSMatthias Ringwald *   disclaimer in the documentation and/or other materials provided  *
327dc86dfdSMatthias Ringwald *   with the distribution.                                           *
337dc86dfdSMatthias Ringwald *                                                                    *
34*779af47bSMatthias Ringwald * o Neither the name of SEGGER Microcontroller GmbH         *
357dc86dfdSMatthias Ringwald *   nor the names of its contributors may be used to endorse or      *
367dc86dfdSMatthias Ringwald *   promote products derived from this software without specific     *
377dc86dfdSMatthias Ringwald *   prior written permission.                                        *
387dc86dfdSMatthias Ringwald *                                                                    *
397dc86dfdSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
407dc86dfdSMatthias Ringwald * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
417dc86dfdSMatthias Ringwald * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
427dc86dfdSMatthias Ringwald * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
437dc86dfdSMatthias Ringwald * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
447dc86dfdSMatthias Ringwald * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
457dc86dfdSMatthias Ringwald * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
467dc86dfdSMatthias Ringwald * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
477dc86dfdSMatthias Ringwald * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
487dc86dfdSMatthias Ringwald * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
497dc86dfdSMatthias Ringwald * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
507dc86dfdSMatthias Ringwald * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
517dc86dfdSMatthias Ringwald * DAMAGE.                                                            *
527dc86dfdSMatthias Ringwald *                                                                    *
537dc86dfdSMatthias Ringwald **********************************************************************
547dc86dfdSMatthias Ringwald ---------------------------END-OF-HEADER------------------------------
557dc86dfdSMatthias Ringwald File    : SEGGER_RTT_printf.c
567dc86dfdSMatthias Ringwald Purpose : Replacement for printf to write formatted data via RTT
57*779af47bSMatthias Ringwald Revision: $Rev: 12360 $
587dc86dfdSMatthias Ringwald ----------------------------------------------------------------------
597dc86dfdSMatthias Ringwald */
607dc86dfdSMatthias Ringwald #include "SEGGER_RTT.h"
617dc86dfdSMatthias Ringwald #include "SEGGER_RTT_Conf.h"
627dc86dfdSMatthias Ringwald 
637dc86dfdSMatthias Ringwald /*********************************************************************
647dc86dfdSMatthias Ringwald *
657dc86dfdSMatthias Ringwald *       Defines, configurable
667dc86dfdSMatthias Ringwald *
677dc86dfdSMatthias Ringwald **********************************************************************
687dc86dfdSMatthias Ringwald */
697dc86dfdSMatthias Ringwald 
707dc86dfdSMatthias Ringwald #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
717dc86dfdSMatthias Ringwald   #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
727dc86dfdSMatthias Ringwald #endif
737dc86dfdSMatthias Ringwald 
747dc86dfdSMatthias Ringwald #include <stdlib.h>
757dc86dfdSMatthias Ringwald #include <stdarg.h>
767dc86dfdSMatthias Ringwald 
777dc86dfdSMatthias Ringwald 
787dc86dfdSMatthias Ringwald #define FORMAT_FLAG_LEFT_JUSTIFY   (1u << 0)
797dc86dfdSMatthias Ringwald #define FORMAT_FLAG_PAD_ZERO       (1u << 1)
807dc86dfdSMatthias Ringwald #define FORMAT_FLAG_PRINT_SIGN     (1u << 2)
817dc86dfdSMatthias Ringwald #define FORMAT_FLAG_ALTERNATE      (1u << 3)
827dc86dfdSMatthias Ringwald 
837dc86dfdSMatthias Ringwald /*********************************************************************
847dc86dfdSMatthias Ringwald *
857dc86dfdSMatthias Ringwald *       Types
867dc86dfdSMatthias Ringwald *
877dc86dfdSMatthias Ringwald **********************************************************************
887dc86dfdSMatthias Ringwald */
897dc86dfdSMatthias Ringwald 
907dc86dfdSMatthias Ringwald typedef struct {
917dc86dfdSMatthias Ringwald   char*     pBuffer;
927dc86dfdSMatthias Ringwald   unsigned  BufferSize;
937dc86dfdSMatthias Ringwald   unsigned  Cnt;
947dc86dfdSMatthias Ringwald 
957dc86dfdSMatthias Ringwald   int   ReturnValue;
967dc86dfdSMatthias Ringwald 
977dc86dfdSMatthias Ringwald   unsigned RTTBufferIndex;
987dc86dfdSMatthias Ringwald } SEGGER_RTT_PRINTF_DESC;
997dc86dfdSMatthias Ringwald 
1007dc86dfdSMatthias Ringwald /*********************************************************************
1017dc86dfdSMatthias Ringwald *
1027dc86dfdSMatthias Ringwald *       Function prototypes
1037dc86dfdSMatthias Ringwald *
1047dc86dfdSMatthias Ringwald **********************************************************************
1057dc86dfdSMatthias Ringwald */
1067dc86dfdSMatthias Ringwald 
1077dc86dfdSMatthias Ringwald /*********************************************************************
1087dc86dfdSMatthias Ringwald *
1097dc86dfdSMatthias Ringwald *       Static code
1107dc86dfdSMatthias Ringwald *
1117dc86dfdSMatthias Ringwald **********************************************************************
1127dc86dfdSMatthias Ringwald */
1137dc86dfdSMatthias Ringwald /*********************************************************************
1147dc86dfdSMatthias Ringwald *
1157dc86dfdSMatthias Ringwald *       _StoreChar
1167dc86dfdSMatthias Ringwald */
1177dc86dfdSMatthias Ringwald static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
1187dc86dfdSMatthias Ringwald   unsigned Cnt;
1197dc86dfdSMatthias Ringwald 
1207dc86dfdSMatthias Ringwald   Cnt = p->Cnt;
1217dc86dfdSMatthias Ringwald   if ((Cnt + 1u) <= p->BufferSize) {
1227dc86dfdSMatthias Ringwald     *(p->pBuffer + Cnt) = c;
1237dc86dfdSMatthias Ringwald     p->Cnt = Cnt + 1u;
1247dc86dfdSMatthias Ringwald     p->ReturnValue++;
1257dc86dfdSMatthias Ringwald   }
1267dc86dfdSMatthias Ringwald   //
1277dc86dfdSMatthias Ringwald   // Write part of string, when the buffer is full
1287dc86dfdSMatthias Ringwald   //
1297dc86dfdSMatthias Ringwald   if (p->Cnt == p->BufferSize) {
1307dc86dfdSMatthias Ringwald     if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
1317dc86dfdSMatthias Ringwald       p->ReturnValue = -1;
1327dc86dfdSMatthias Ringwald     } else {
1337dc86dfdSMatthias Ringwald       p->Cnt = 0u;
1347dc86dfdSMatthias Ringwald     }
1357dc86dfdSMatthias Ringwald   }
1367dc86dfdSMatthias Ringwald }
1377dc86dfdSMatthias Ringwald 
1387dc86dfdSMatthias Ringwald /*********************************************************************
1397dc86dfdSMatthias Ringwald *
1407dc86dfdSMatthias Ringwald *       _PrintUnsigned
1417dc86dfdSMatthias Ringwald */
1427dc86dfdSMatthias Ringwald static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
1437dc86dfdSMatthias Ringwald   static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1447dc86dfdSMatthias Ringwald   unsigned Div;
1457dc86dfdSMatthias Ringwald   unsigned Digit;
1467dc86dfdSMatthias Ringwald   unsigned Number;
1477dc86dfdSMatthias Ringwald   unsigned Width;
1487dc86dfdSMatthias Ringwald   char c;
1497dc86dfdSMatthias Ringwald 
1507dc86dfdSMatthias Ringwald   Number = v;
1517dc86dfdSMatthias Ringwald   Digit = 1u;
1527dc86dfdSMatthias Ringwald   //
1537dc86dfdSMatthias Ringwald   // Get actual field width
1547dc86dfdSMatthias Ringwald   //
1557dc86dfdSMatthias Ringwald   Width = 1u;
1567dc86dfdSMatthias Ringwald   while (Number >= Base) {
1577dc86dfdSMatthias Ringwald     Number = (Number / Base);
1587dc86dfdSMatthias Ringwald     Width++;
1597dc86dfdSMatthias Ringwald   }
1607dc86dfdSMatthias Ringwald   if (NumDigits > Width) {
1617dc86dfdSMatthias Ringwald     Width = NumDigits;
1627dc86dfdSMatthias Ringwald   }
1637dc86dfdSMatthias Ringwald   //
1647dc86dfdSMatthias Ringwald   // Print leading chars if necessary
1657dc86dfdSMatthias Ringwald   //
1667dc86dfdSMatthias Ringwald   if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
1677dc86dfdSMatthias Ringwald     if (FieldWidth != 0u) {
1687dc86dfdSMatthias Ringwald       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
1697dc86dfdSMatthias Ringwald         c = '0';
1707dc86dfdSMatthias Ringwald       } else {
1717dc86dfdSMatthias Ringwald         c = ' ';
1727dc86dfdSMatthias Ringwald       }
1737dc86dfdSMatthias Ringwald       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
1747dc86dfdSMatthias Ringwald         FieldWidth--;
1757dc86dfdSMatthias Ringwald         _StoreChar(pBufferDesc, c);
1767dc86dfdSMatthias Ringwald         if (pBufferDesc->ReturnValue < 0) {
1777dc86dfdSMatthias Ringwald           break;
1787dc86dfdSMatthias Ringwald         }
1797dc86dfdSMatthias Ringwald       }
1807dc86dfdSMatthias Ringwald     }
1817dc86dfdSMatthias Ringwald   }
1827dc86dfdSMatthias Ringwald   if (pBufferDesc->ReturnValue >= 0) {
1837dc86dfdSMatthias Ringwald     //
1847dc86dfdSMatthias Ringwald     // Compute Digit.
1857dc86dfdSMatthias Ringwald     // Loop until Digit has the value of the highest digit required.
1867dc86dfdSMatthias Ringwald     // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
1877dc86dfdSMatthias Ringwald     //
1887dc86dfdSMatthias Ringwald     while (1) {
1897dc86dfdSMatthias Ringwald       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)
1907dc86dfdSMatthias Ringwald         NumDigits--;
1917dc86dfdSMatthias Ringwald       } else {
1927dc86dfdSMatthias Ringwald         Div = v / Digit;
1937dc86dfdSMatthias Ringwald         if (Div < Base) {        // Is our divider big enough to extract the highest digit from value? => Done
1947dc86dfdSMatthias Ringwald           break;
1957dc86dfdSMatthias Ringwald         }
1967dc86dfdSMatthias Ringwald       }
1977dc86dfdSMatthias Ringwald       Digit *= Base;
1987dc86dfdSMatthias Ringwald     }
1997dc86dfdSMatthias Ringwald     //
2007dc86dfdSMatthias Ringwald     // Output digits
2017dc86dfdSMatthias Ringwald     //
2027dc86dfdSMatthias Ringwald     do {
2037dc86dfdSMatthias Ringwald       Div = v / Digit;
2047dc86dfdSMatthias Ringwald       v -= Div * Digit;
2057dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, _aV2C[Div]);
2067dc86dfdSMatthias Ringwald       if (pBufferDesc->ReturnValue < 0) {
2077dc86dfdSMatthias Ringwald         break;
2087dc86dfdSMatthias Ringwald       }
2097dc86dfdSMatthias Ringwald       Digit /= Base;
2107dc86dfdSMatthias Ringwald     } while (Digit);
2117dc86dfdSMatthias Ringwald     //
2127dc86dfdSMatthias Ringwald     // Print trailing spaces if necessary
2137dc86dfdSMatthias Ringwald     //
2147dc86dfdSMatthias Ringwald     if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
2157dc86dfdSMatthias Ringwald       if (FieldWidth != 0u) {
2167dc86dfdSMatthias Ringwald         while ((FieldWidth != 0u) && (Width < FieldWidth)) {
2177dc86dfdSMatthias Ringwald           FieldWidth--;
2187dc86dfdSMatthias Ringwald           _StoreChar(pBufferDesc, ' ');
2197dc86dfdSMatthias Ringwald           if (pBufferDesc->ReturnValue < 0) {
2207dc86dfdSMatthias Ringwald             break;
2217dc86dfdSMatthias Ringwald           }
2227dc86dfdSMatthias Ringwald         }
2237dc86dfdSMatthias Ringwald       }
2247dc86dfdSMatthias Ringwald     }
2257dc86dfdSMatthias Ringwald   }
2267dc86dfdSMatthias Ringwald }
2277dc86dfdSMatthias Ringwald 
2287dc86dfdSMatthias Ringwald /*********************************************************************
2297dc86dfdSMatthias Ringwald *
2307dc86dfdSMatthias Ringwald *       _PrintInt
2317dc86dfdSMatthias Ringwald */
2327dc86dfdSMatthias Ringwald static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
2337dc86dfdSMatthias Ringwald   unsigned Width;
2347dc86dfdSMatthias Ringwald   int Number;
2357dc86dfdSMatthias Ringwald 
2367dc86dfdSMatthias Ringwald   Number = (v < 0) ? -v : v;
2377dc86dfdSMatthias Ringwald 
2387dc86dfdSMatthias Ringwald   //
2397dc86dfdSMatthias Ringwald   // Get actual field width
2407dc86dfdSMatthias Ringwald   //
2417dc86dfdSMatthias Ringwald   Width = 1u;
2427dc86dfdSMatthias Ringwald   while (Number >= (int)Base) {
2437dc86dfdSMatthias Ringwald     Number = (Number / (int)Base);
2447dc86dfdSMatthias Ringwald     Width++;
2457dc86dfdSMatthias Ringwald   }
2467dc86dfdSMatthias Ringwald   if (NumDigits > Width) {
2477dc86dfdSMatthias Ringwald     Width = NumDigits;
2487dc86dfdSMatthias Ringwald   }
2497dc86dfdSMatthias Ringwald   if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
2507dc86dfdSMatthias Ringwald     FieldWidth--;
2517dc86dfdSMatthias Ringwald   }
2527dc86dfdSMatthias Ringwald 
2537dc86dfdSMatthias Ringwald   //
2547dc86dfdSMatthias Ringwald   // Print leading spaces if necessary
2557dc86dfdSMatthias Ringwald   //
2567dc86dfdSMatthias Ringwald   if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
2577dc86dfdSMatthias Ringwald     if (FieldWidth != 0u) {
2587dc86dfdSMatthias Ringwald       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
2597dc86dfdSMatthias Ringwald         FieldWidth--;
2607dc86dfdSMatthias Ringwald         _StoreChar(pBufferDesc, ' ');
2617dc86dfdSMatthias Ringwald         if (pBufferDesc->ReturnValue < 0) {
2627dc86dfdSMatthias Ringwald           break;
2637dc86dfdSMatthias Ringwald         }
2647dc86dfdSMatthias Ringwald       }
2657dc86dfdSMatthias Ringwald     }
2667dc86dfdSMatthias Ringwald   }
2677dc86dfdSMatthias Ringwald   //
2687dc86dfdSMatthias Ringwald   // Print sign if necessary
2697dc86dfdSMatthias Ringwald   //
2707dc86dfdSMatthias Ringwald   if (pBufferDesc->ReturnValue >= 0) {
2717dc86dfdSMatthias Ringwald     if (v < 0) {
2727dc86dfdSMatthias Ringwald       v = -v;
2737dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, '-');
2747dc86dfdSMatthias Ringwald     } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
2757dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, '+');
2767dc86dfdSMatthias Ringwald     } else {
2777dc86dfdSMatthias Ringwald 
2787dc86dfdSMatthias Ringwald     }
2797dc86dfdSMatthias Ringwald     if (pBufferDesc->ReturnValue >= 0) {
2807dc86dfdSMatthias Ringwald       //
2817dc86dfdSMatthias Ringwald       // Print leading zeros if necessary
2827dc86dfdSMatthias Ringwald       //
2837dc86dfdSMatthias Ringwald       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
2847dc86dfdSMatthias Ringwald         if (FieldWidth != 0u) {
2857dc86dfdSMatthias Ringwald           while ((FieldWidth != 0u) && (Width < FieldWidth)) {
2867dc86dfdSMatthias Ringwald             FieldWidth--;
2877dc86dfdSMatthias Ringwald             _StoreChar(pBufferDesc, '0');
2887dc86dfdSMatthias Ringwald             if (pBufferDesc->ReturnValue < 0) {
2897dc86dfdSMatthias Ringwald               break;
2907dc86dfdSMatthias Ringwald             }
2917dc86dfdSMatthias Ringwald           }
2927dc86dfdSMatthias Ringwald         }
2937dc86dfdSMatthias Ringwald       }
2947dc86dfdSMatthias Ringwald       if (pBufferDesc->ReturnValue >= 0) {
2957dc86dfdSMatthias Ringwald         //
2967dc86dfdSMatthias Ringwald         // Print number without sign
2977dc86dfdSMatthias Ringwald         //
2987dc86dfdSMatthias Ringwald         _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
2997dc86dfdSMatthias Ringwald       }
3007dc86dfdSMatthias Ringwald     }
3017dc86dfdSMatthias Ringwald   }
3027dc86dfdSMatthias Ringwald }
3037dc86dfdSMatthias Ringwald 
3047dc86dfdSMatthias Ringwald /*********************************************************************
3057dc86dfdSMatthias Ringwald *
3067dc86dfdSMatthias Ringwald *       Public code
3077dc86dfdSMatthias Ringwald *
3087dc86dfdSMatthias Ringwald **********************************************************************
3097dc86dfdSMatthias Ringwald */
3107dc86dfdSMatthias Ringwald /*********************************************************************
3117dc86dfdSMatthias Ringwald *
3127dc86dfdSMatthias Ringwald *       SEGGER_RTT_vprintf
3137dc86dfdSMatthias Ringwald *
3147dc86dfdSMatthias Ringwald *  Function description
3157dc86dfdSMatthias Ringwald *    Stores a formatted string in SEGGER RTT control block.
3167dc86dfdSMatthias Ringwald *    This data is read by the host.
3177dc86dfdSMatthias Ringwald *
3187dc86dfdSMatthias Ringwald *  Parameters
3197dc86dfdSMatthias Ringwald *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
3207dc86dfdSMatthias Ringwald *    sFormat      Pointer to format string
3217dc86dfdSMatthias Ringwald *    pParamList   Pointer to the list of arguments for the format string
3227dc86dfdSMatthias Ringwald *
3237dc86dfdSMatthias Ringwald *  Return values
3247dc86dfdSMatthias Ringwald *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
3257dc86dfdSMatthias Ringwald *     < 0:  Error
3267dc86dfdSMatthias Ringwald */
3277dc86dfdSMatthias Ringwald int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
3287dc86dfdSMatthias Ringwald   char c;
3297dc86dfdSMatthias Ringwald   SEGGER_RTT_PRINTF_DESC BufferDesc;
3307dc86dfdSMatthias Ringwald   int v;
3317dc86dfdSMatthias Ringwald   unsigned NumDigits;
3327dc86dfdSMatthias Ringwald   unsigned FormatFlags;
3337dc86dfdSMatthias Ringwald   unsigned FieldWidth;
3347dc86dfdSMatthias Ringwald   char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
3357dc86dfdSMatthias Ringwald 
3367dc86dfdSMatthias Ringwald   BufferDesc.pBuffer        = acBuffer;
3377dc86dfdSMatthias Ringwald   BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
3387dc86dfdSMatthias Ringwald   BufferDesc.Cnt            = 0u;
3397dc86dfdSMatthias Ringwald   BufferDesc.RTTBufferIndex = BufferIndex;
3407dc86dfdSMatthias Ringwald   BufferDesc.ReturnValue    = 0;
3417dc86dfdSMatthias Ringwald 
3427dc86dfdSMatthias Ringwald   do {
3437dc86dfdSMatthias Ringwald     c = *sFormat;
3447dc86dfdSMatthias Ringwald     sFormat++;
3457dc86dfdSMatthias Ringwald     if (c == 0u) {
3467dc86dfdSMatthias Ringwald       break;
3477dc86dfdSMatthias Ringwald     }
3487dc86dfdSMatthias Ringwald     if (c == '%') {
3497dc86dfdSMatthias Ringwald       //
3507dc86dfdSMatthias Ringwald       // Filter out flags
3517dc86dfdSMatthias Ringwald       //
3527dc86dfdSMatthias Ringwald       FormatFlags = 0u;
3537dc86dfdSMatthias Ringwald       v = 1;
3547dc86dfdSMatthias Ringwald       do {
3557dc86dfdSMatthias Ringwald         c = *sFormat;
3567dc86dfdSMatthias Ringwald         switch (c) {
3577dc86dfdSMatthias Ringwald         case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
3587dc86dfdSMatthias Ringwald         case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
3597dc86dfdSMatthias Ringwald         case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
3607dc86dfdSMatthias Ringwald         case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
3617dc86dfdSMatthias Ringwald         default:  v = 0; break;
3627dc86dfdSMatthias Ringwald         }
3637dc86dfdSMatthias Ringwald       } while (v);
3647dc86dfdSMatthias Ringwald       //
3657dc86dfdSMatthias Ringwald       // filter out field with
3667dc86dfdSMatthias Ringwald       //
3677dc86dfdSMatthias Ringwald       FieldWidth = 0u;
3687dc86dfdSMatthias Ringwald       do {
3697dc86dfdSMatthias Ringwald         c = *sFormat;
3707dc86dfdSMatthias Ringwald         if ((c < '0') || (c > '9')) {
3717dc86dfdSMatthias Ringwald           break;
3727dc86dfdSMatthias Ringwald         }
3737dc86dfdSMatthias Ringwald         sFormat++;
3747dc86dfdSMatthias Ringwald         FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
3757dc86dfdSMatthias Ringwald       } while (1);
3767dc86dfdSMatthias Ringwald 
3777dc86dfdSMatthias Ringwald       //
3787dc86dfdSMatthias Ringwald       // Filter out precision (number of digits to display)
3797dc86dfdSMatthias Ringwald       //
3807dc86dfdSMatthias Ringwald       NumDigits = 0u;
3817dc86dfdSMatthias Ringwald       c = *sFormat;
3827dc86dfdSMatthias Ringwald       if (c == '.') {
3837dc86dfdSMatthias Ringwald         sFormat++;
3847dc86dfdSMatthias Ringwald         do {
3857dc86dfdSMatthias Ringwald           c = *sFormat;
3867dc86dfdSMatthias Ringwald           if ((c < '0') || (c > '9')) {
3877dc86dfdSMatthias Ringwald             break;
3887dc86dfdSMatthias Ringwald           }
3897dc86dfdSMatthias Ringwald           sFormat++;
3907dc86dfdSMatthias Ringwald           NumDigits = NumDigits * 10u + ((unsigned)c - '0');
3917dc86dfdSMatthias Ringwald         } while (1);
3927dc86dfdSMatthias Ringwald       }
3937dc86dfdSMatthias Ringwald       //
3947dc86dfdSMatthias Ringwald       // Filter out length modifier
3957dc86dfdSMatthias Ringwald       //
3967dc86dfdSMatthias Ringwald       c = *sFormat;
3977dc86dfdSMatthias Ringwald       do {
3987dc86dfdSMatthias Ringwald         if ((c == 'l') || (c == 'h')) {
3997dc86dfdSMatthias Ringwald           sFormat++;
4007dc86dfdSMatthias Ringwald           c = *sFormat;
4017dc86dfdSMatthias Ringwald         } else {
4027dc86dfdSMatthias Ringwald           break;
4037dc86dfdSMatthias Ringwald         }
4047dc86dfdSMatthias Ringwald       } while (1);
4057dc86dfdSMatthias Ringwald       //
4067dc86dfdSMatthias Ringwald       // Handle specifiers
4077dc86dfdSMatthias Ringwald       //
4087dc86dfdSMatthias Ringwald       switch (c) {
4097dc86dfdSMatthias Ringwald       case 'c': {
4107dc86dfdSMatthias Ringwald         char c0;
4117dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
4127dc86dfdSMatthias Ringwald         c0 = (char)v;
4137dc86dfdSMatthias Ringwald         _StoreChar(&BufferDesc, c0);
4147dc86dfdSMatthias Ringwald         break;
4157dc86dfdSMatthias Ringwald       }
4167dc86dfdSMatthias Ringwald       case 'd':
4177dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
4187dc86dfdSMatthias Ringwald         _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
4197dc86dfdSMatthias Ringwald         break;
4207dc86dfdSMatthias Ringwald       case 'u':
4217dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
4227dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
4237dc86dfdSMatthias Ringwald         break;
4247dc86dfdSMatthias Ringwald       case 'x':
4257dc86dfdSMatthias Ringwald       case 'X':
4267dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
4277dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
4287dc86dfdSMatthias Ringwald         break;
4297dc86dfdSMatthias Ringwald       case 's':
4307dc86dfdSMatthias Ringwald         {
4317dc86dfdSMatthias Ringwald           const char * s = va_arg(*pParamList, const char *);
4327dc86dfdSMatthias Ringwald           do {
4337dc86dfdSMatthias Ringwald             c = *s;
4347dc86dfdSMatthias Ringwald             s++;
4357dc86dfdSMatthias Ringwald             if (c == '\0') {
4367dc86dfdSMatthias Ringwald               break;
4377dc86dfdSMatthias Ringwald             }
4387dc86dfdSMatthias Ringwald            _StoreChar(&BufferDesc, c);
4397dc86dfdSMatthias Ringwald           } while (BufferDesc.ReturnValue >= 0);
4407dc86dfdSMatthias Ringwald         }
4417dc86dfdSMatthias Ringwald         break;
4427dc86dfdSMatthias Ringwald       case 'p':
4437dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
4447dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
4457dc86dfdSMatthias Ringwald         break;
4467dc86dfdSMatthias Ringwald       case '%':
4477dc86dfdSMatthias Ringwald         _StoreChar(&BufferDesc, '%');
4487dc86dfdSMatthias Ringwald         break;
4497dc86dfdSMatthias Ringwald       default:
4507dc86dfdSMatthias Ringwald         break;
4517dc86dfdSMatthias Ringwald       }
4527dc86dfdSMatthias Ringwald       sFormat++;
4537dc86dfdSMatthias Ringwald     } else {
4547dc86dfdSMatthias Ringwald       _StoreChar(&BufferDesc, c);
4557dc86dfdSMatthias Ringwald     }
4567dc86dfdSMatthias Ringwald   } while (BufferDesc.ReturnValue >= 0);
4577dc86dfdSMatthias Ringwald 
4587dc86dfdSMatthias Ringwald   if (BufferDesc.ReturnValue > 0) {
4597dc86dfdSMatthias Ringwald     //
4607dc86dfdSMatthias Ringwald     // Write remaining data, if any
4617dc86dfdSMatthias Ringwald     //
4627dc86dfdSMatthias Ringwald     if (BufferDesc.Cnt != 0u) {
4637dc86dfdSMatthias Ringwald       SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
4647dc86dfdSMatthias Ringwald     }
4657dc86dfdSMatthias Ringwald     BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
4667dc86dfdSMatthias Ringwald   }
4677dc86dfdSMatthias Ringwald   return BufferDesc.ReturnValue;
4687dc86dfdSMatthias Ringwald }
4697dc86dfdSMatthias Ringwald 
4707dc86dfdSMatthias Ringwald /*********************************************************************
4717dc86dfdSMatthias Ringwald *
4727dc86dfdSMatthias Ringwald *       SEGGER_RTT_printf
4737dc86dfdSMatthias Ringwald *
4747dc86dfdSMatthias Ringwald *  Function description
4757dc86dfdSMatthias Ringwald *    Stores a formatted string in SEGGER RTT control block.
4767dc86dfdSMatthias Ringwald *    This data is read by the host.
4777dc86dfdSMatthias Ringwald *
4787dc86dfdSMatthias Ringwald *  Parameters
4797dc86dfdSMatthias Ringwald *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
4807dc86dfdSMatthias Ringwald *    sFormat      Pointer to format string, followed by the arguments for conversion
4817dc86dfdSMatthias Ringwald *
4827dc86dfdSMatthias Ringwald *  Return values
4837dc86dfdSMatthias Ringwald *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
4847dc86dfdSMatthias Ringwald *     < 0:  Error
4857dc86dfdSMatthias Ringwald *
4867dc86dfdSMatthias Ringwald *  Notes
4877dc86dfdSMatthias Ringwald *    (1) Conversion specifications have following syntax:
4887dc86dfdSMatthias Ringwald *          %[flags][FieldWidth][.Precision]ConversionSpecifier
4897dc86dfdSMatthias Ringwald *    (2) Supported flags:
4907dc86dfdSMatthias Ringwald *          -: Left justify within the field width
4917dc86dfdSMatthias Ringwald *          +: Always print sign extension for signed conversions
4927dc86dfdSMatthias Ringwald *          0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
4937dc86dfdSMatthias Ringwald *        Supported conversion specifiers:
4947dc86dfdSMatthias Ringwald *          c: Print the argument as one char
4957dc86dfdSMatthias Ringwald *          d: Print the argument as a signed integer
4967dc86dfdSMatthias Ringwald *          u: Print the argument as an unsigned integer
4977dc86dfdSMatthias Ringwald *          x: Print the argument as an hexadecimal integer
4987dc86dfdSMatthias Ringwald *          s: Print the string pointed to by the argument
4997dc86dfdSMatthias Ringwald *          p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
5007dc86dfdSMatthias Ringwald */
5017dc86dfdSMatthias Ringwald int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
5027dc86dfdSMatthias Ringwald   int r;
5037dc86dfdSMatthias Ringwald   va_list ParamList;
5047dc86dfdSMatthias Ringwald 
5057dc86dfdSMatthias Ringwald   va_start(ParamList, sFormat);
5067dc86dfdSMatthias Ringwald   r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
5077dc86dfdSMatthias Ringwald   va_end(ParamList);
5087dc86dfdSMatthias Ringwald   return r;
5097dc86dfdSMatthias Ringwald }
5107dc86dfdSMatthias Ringwald /*************************** End of file ****************************/
511