xref: /btstack/3rd-party/segger-rtt/SEGGER_RTT_printf.c (revision 7dc86dfd3569d69491d87d64749fd45afb46c67a)
1*7dc86dfdSMatthias Ringwald /*********************************************************************
2*7dc86dfdSMatthias Ringwald *               SEGGER MICROCONTROLLER GmbH & Co. KG                 *
3*7dc86dfdSMatthias Ringwald *       Solutions for real time microcontroller applications         *
4*7dc86dfdSMatthias Ringwald **********************************************************************
5*7dc86dfdSMatthias Ringwald *                                                                    *
6*7dc86dfdSMatthias Ringwald *       (c) 2014 - 2016  SEGGER Microcontroller GmbH & Co. KG        *
7*7dc86dfdSMatthias Ringwald *                                                                    *
8*7dc86dfdSMatthias Ringwald *       www.segger.com     Support: [email protected]               *
9*7dc86dfdSMatthias Ringwald *                                                                    *
10*7dc86dfdSMatthias Ringwald **********************************************************************
11*7dc86dfdSMatthias Ringwald *                                                                    *
12*7dc86dfdSMatthias Ringwald *       SEGGER RTT * Real Time Transfer for embedded targets         *
13*7dc86dfdSMatthias Ringwald *                                                                    *
14*7dc86dfdSMatthias Ringwald **********************************************************************
15*7dc86dfdSMatthias Ringwald *                                                                    *
16*7dc86dfdSMatthias Ringwald * All rights reserved.                                               *
17*7dc86dfdSMatthias Ringwald *                                                                    *
18*7dc86dfdSMatthias Ringwald * SEGGER strongly recommends to not make any changes                 *
19*7dc86dfdSMatthias Ringwald * to or modify the source code of this software in order to stay     *
20*7dc86dfdSMatthias Ringwald * compatible with the RTT protocol and J-Link.                       *
21*7dc86dfdSMatthias Ringwald *                                                                    *
22*7dc86dfdSMatthias Ringwald * Redistribution and use in source and binary forms, with or         *
23*7dc86dfdSMatthias Ringwald * without modification, are permitted provided that the following    *
24*7dc86dfdSMatthias Ringwald * conditions are met:                                                *
25*7dc86dfdSMatthias Ringwald *                                                                    *
26*7dc86dfdSMatthias Ringwald * o Redistributions of source code must retain the above copyright   *
27*7dc86dfdSMatthias Ringwald *   notice, this list of conditions and the following disclaimer.    *
28*7dc86dfdSMatthias Ringwald *                                                                    *
29*7dc86dfdSMatthias Ringwald * o Redistributions in binary form must reproduce the above          *
30*7dc86dfdSMatthias Ringwald *   copyright notice, this list of conditions and the following      *
31*7dc86dfdSMatthias Ringwald *   disclaimer in the documentation and/or other materials provided  *
32*7dc86dfdSMatthias Ringwald *   with the distribution.                                           *
33*7dc86dfdSMatthias Ringwald *                                                                    *
34*7dc86dfdSMatthias Ringwald * o Neither the name of SEGGER Microcontroller GmbH & Co. KG         *
35*7dc86dfdSMatthias Ringwald *   nor the names of its contributors may be used to endorse or      *
36*7dc86dfdSMatthias Ringwald *   promote products derived from this software without specific     *
37*7dc86dfdSMatthias Ringwald *   prior written permission.                                        *
38*7dc86dfdSMatthias Ringwald *                                                                    *
39*7dc86dfdSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
40*7dc86dfdSMatthias Ringwald * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
41*7dc86dfdSMatthias Ringwald * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
42*7dc86dfdSMatthias Ringwald * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
43*7dc86dfdSMatthias Ringwald * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
44*7dc86dfdSMatthias Ringwald * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
45*7dc86dfdSMatthias Ringwald * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
46*7dc86dfdSMatthias Ringwald * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
47*7dc86dfdSMatthias Ringwald * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
48*7dc86dfdSMatthias Ringwald * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
49*7dc86dfdSMatthias Ringwald * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
50*7dc86dfdSMatthias Ringwald * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
51*7dc86dfdSMatthias Ringwald * DAMAGE.                                                            *
52*7dc86dfdSMatthias Ringwald *                                                                    *
53*7dc86dfdSMatthias Ringwald **********************************************************************
54*7dc86dfdSMatthias Ringwald ---------------------------END-OF-HEADER------------------------------
55*7dc86dfdSMatthias Ringwald File    : SEGGER_RTT_printf.c
56*7dc86dfdSMatthias Ringwald Purpose : Replacement for printf to write formatted data via RTT
57*7dc86dfdSMatthias Ringwald Revision: $Rev: 4351 $
58*7dc86dfdSMatthias Ringwald ----------------------------------------------------------------------
59*7dc86dfdSMatthias Ringwald */
60*7dc86dfdSMatthias Ringwald #include "SEGGER_RTT.h"
61*7dc86dfdSMatthias Ringwald #include "SEGGER_RTT_Conf.h"
62*7dc86dfdSMatthias Ringwald 
63*7dc86dfdSMatthias Ringwald /*********************************************************************
64*7dc86dfdSMatthias Ringwald *
65*7dc86dfdSMatthias Ringwald *       Defines, configurable
66*7dc86dfdSMatthias Ringwald *
67*7dc86dfdSMatthias Ringwald **********************************************************************
68*7dc86dfdSMatthias Ringwald */
69*7dc86dfdSMatthias Ringwald 
70*7dc86dfdSMatthias Ringwald #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
71*7dc86dfdSMatthias Ringwald   #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
72*7dc86dfdSMatthias Ringwald #endif
73*7dc86dfdSMatthias Ringwald 
74*7dc86dfdSMatthias Ringwald #include <stdlib.h>
75*7dc86dfdSMatthias Ringwald #include <stdarg.h>
76*7dc86dfdSMatthias Ringwald 
77*7dc86dfdSMatthias Ringwald 
78*7dc86dfdSMatthias Ringwald #define FORMAT_FLAG_LEFT_JUSTIFY   (1u << 0)
79*7dc86dfdSMatthias Ringwald #define FORMAT_FLAG_PAD_ZERO       (1u << 1)
80*7dc86dfdSMatthias Ringwald #define FORMAT_FLAG_PRINT_SIGN     (1u << 2)
81*7dc86dfdSMatthias Ringwald #define FORMAT_FLAG_ALTERNATE      (1u << 3)
82*7dc86dfdSMatthias Ringwald 
83*7dc86dfdSMatthias Ringwald /*********************************************************************
84*7dc86dfdSMatthias Ringwald *
85*7dc86dfdSMatthias Ringwald *       Types
86*7dc86dfdSMatthias Ringwald *
87*7dc86dfdSMatthias Ringwald **********************************************************************
88*7dc86dfdSMatthias Ringwald */
89*7dc86dfdSMatthias Ringwald 
90*7dc86dfdSMatthias Ringwald typedef struct {
91*7dc86dfdSMatthias Ringwald   char*     pBuffer;
92*7dc86dfdSMatthias Ringwald   unsigned  BufferSize;
93*7dc86dfdSMatthias Ringwald   unsigned  Cnt;
94*7dc86dfdSMatthias Ringwald 
95*7dc86dfdSMatthias Ringwald   int   ReturnValue;
96*7dc86dfdSMatthias Ringwald 
97*7dc86dfdSMatthias Ringwald   unsigned RTTBufferIndex;
98*7dc86dfdSMatthias Ringwald } SEGGER_RTT_PRINTF_DESC;
99*7dc86dfdSMatthias Ringwald 
100*7dc86dfdSMatthias Ringwald /*********************************************************************
101*7dc86dfdSMatthias Ringwald *
102*7dc86dfdSMatthias Ringwald *       Function prototypes
103*7dc86dfdSMatthias Ringwald *
104*7dc86dfdSMatthias Ringwald **********************************************************************
105*7dc86dfdSMatthias Ringwald */
106*7dc86dfdSMatthias Ringwald int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
107*7dc86dfdSMatthias Ringwald 
108*7dc86dfdSMatthias Ringwald /*********************************************************************
109*7dc86dfdSMatthias Ringwald *
110*7dc86dfdSMatthias Ringwald *       Static code
111*7dc86dfdSMatthias Ringwald *
112*7dc86dfdSMatthias Ringwald **********************************************************************
113*7dc86dfdSMatthias Ringwald */
114*7dc86dfdSMatthias Ringwald /*********************************************************************
115*7dc86dfdSMatthias Ringwald *
116*7dc86dfdSMatthias Ringwald *       _StoreChar
117*7dc86dfdSMatthias Ringwald */
118*7dc86dfdSMatthias Ringwald static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
119*7dc86dfdSMatthias Ringwald   unsigned Cnt;
120*7dc86dfdSMatthias Ringwald 
121*7dc86dfdSMatthias Ringwald   Cnt = p->Cnt;
122*7dc86dfdSMatthias Ringwald   if ((Cnt + 1u) <= p->BufferSize) {
123*7dc86dfdSMatthias Ringwald     *(p->pBuffer + Cnt) = c;
124*7dc86dfdSMatthias Ringwald     p->Cnt = Cnt + 1u;
125*7dc86dfdSMatthias Ringwald     p->ReturnValue++;
126*7dc86dfdSMatthias Ringwald   }
127*7dc86dfdSMatthias Ringwald   //
128*7dc86dfdSMatthias Ringwald   // Write part of string, when the buffer is full
129*7dc86dfdSMatthias Ringwald   //
130*7dc86dfdSMatthias Ringwald   if (p->Cnt == p->BufferSize) {
131*7dc86dfdSMatthias Ringwald     if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
132*7dc86dfdSMatthias Ringwald       p->ReturnValue = -1;
133*7dc86dfdSMatthias Ringwald     } else {
134*7dc86dfdSMatthias Ringwald       p->Cnt = 0u;
135*7dc86dfdSMatthias Ringwald     }
136*7dc86dfdSMatthias Ringwald   }
137*7dc86dfdSMatthias Ringwald }
138*7dc86dfdSMatthias Ringwald 
139*7dc86dfdSMatthias Ringwald /*********************************************************************
140*7dc86dfdSMatthias Ringwald *
141*7dc86dfdSMatthias Ringwald *       _PrintUnsigned
142*7dc86dfdSMatthias Ringwald */
143*7dc86dfdSMatthias Ringwald static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
144*7dc86dfdSMatthias Ringwald   static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
145*7dc86dfdSMatthias Ringwald   unsigned Div;
146*7dc86dfdSMatthias Ringwald   unsigned Digit;
147*7dc86dfdSMatthias Ringwald   unsigned Number;
148*7dc86dfdSMatthias Ringwald   unsigned Width;
149*7dc86dfdSMatthias Ringwald   char c;
150*7dc86dfdSMatthias Ringwald 
151*7dc86dfdSMatthias Ringwald   Number = v;
152*7dc86dfdSMatthias Ringwald   Digit = 1u;
153*7dc86dfdSMatthias Ringwald   //
154*7dc86dfdSMatthias Ringwald   // Get actual field width
155*7dc86dfdSMatthias Ringwald   //
156*7dc86dfdSMatthias Ringwald   Width = 1u;
157*7dc86dfdSMatthias Ringwald   while (Number >= Base) {
158*7dc86dfdSMatthias Ringwald     Number = (Number / Base);
159*7dc86dfdSMatthias Ringwald     Width++;
160*7dc86dfdSMatthias Ringwald   }
161*7dc86dfdSMatthias Ringwald   if (NumDigits > Width) {
162*7dc86dfdSMatthias Ringwald     Width = NumDigits;
163*7dc86dfdSMatthias Ringwald   }
164*7dc86dfdSMatthias Ringwald   //
165*7dc86dfdSMatthias Ringwald   // Print leading chars if necessary
166*7dc86dfdSMatthias Ringwald   //
167*7dc86dfdSMatthias Ringwald   if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
168*7dc86dfdSMatthias Ringwald     if (FieldWidth != 0u) {
169*7dc86dfdSMatthias Ringwald       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
170*7dc86dfdSMatthias Ringwald         c = '0';
171*7dc86dfdSMatthias Ringwald       } else {
172*7dc86dfdSMatthias Ringwald         c = ' ';
173*7dc86dfdSMatthias Ringwald       }
174*7dc86dfdSMatthias Ringwald       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
175*7dc86dfdSMatthias Ringwald         FieldWidth--;
176*7dc86dfdSMatthias Ringwald         _StoreChar(pBufferDesc, c);
177*7dc86dfdSMatthias Ringwald         if (pBufferDesc->ReturnValue < 0) {
178*7dc86dfdSMatthias Ringwald           break;
179*7dc86dfdSMatthias Ringwald         }
180*7dc86dfdSMatthias Ringwald       }
181*7dc86dfdSMatthias Ringwald     }
182*7dc86dfdSMatthias Ringwald   }
183*7dc86dfdSMatthias Ringwald   if (pBufferDesc->ReturnValue >= 0) {
184*7dc86dfdSMatthias Ringwald     //
185*7dc86dfdSMatthias Ringwald     // Compute Digit.
186*7dc86dfdSMatthias Ringwald     // Loop until Digit has the value of the highest digit required.
187*7dc86dfdSMatthias Ringwald     // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
188*7dc86dfdSMatthias Ringwald     //
189*7dc86dfdSMatthias Ringwald     while (1) {
190*7dc86dfdSMatthias 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)
191*7dc86dfdSMatthias Ringwald         NumDigits--;
192*7dc86dfdSMatthias Ringwald       } else {
193*7dc86dfdSMatthias Ringwald         Div = v / Digit;
194*7dc86dfdSMatthias Ringwald         if (Div < Base) {        // Is our divider big enough to extract the highest digit from value? => Done
195*7dc86dfdSMatthias Ringwald           break;
196*7dc86dfdSMatthias Ringwald         }
197*7dc86dfdSMatthias Ringwald       }
198*7dc86dfdSMatthias Ringwald       Digit *= Base;
199*7dc86dfdSMatthias Ringwald     }
200*7dc86dfdSMatthias Ringwald     //
201*7dc86dfdSMatthias Ringwald     // Output digits
202*7dc86dfdSMatthias Ringwald     //
203*7dc86dfdSMatthias Ringwald     do {
204*7dc86dfdSMatthias Ringwald       Div = v / Digit;
205*7dc86dfdSMatthias Ringwald       v -= Div * Digit;
206*7dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, _aV2C[Div]);
207*7dc86dfdSMatthias Ringwald       if (pBufferDesc->ReturnValue < 0) {
208*7dc86dfdSMatthias Ringwald         break;
209*7dc86dfdSMatthias Ringwald       }
210*7dc86dfdSMatthias Ringwald       Digit /= Base;
211*7dc86dfdSMatthias Ringwald     } while (Digit);
212*7dc86dfdSMatthias Ringwald     //
213*7dc86dfdSMatthias Ringwald     // Print trailing spaces if necessary
214*7dc86dfdSMatthias Ringwald     //
215*7dc86dfdSMatthias Ringwald     if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
216*7dc86dfdSMatthias Ringwald       if (FieldWidth != 0u) {
217*7dc86dfdSMatthias Ringwald         while ((FieldWidth != 0u) && (Width < FieldWidth)) {
218*7dc86dfdSMatthias Ringwald           FieldWidth--;
219*7dc86dfdSMatthias Ringwald           _StoreChar(pBufferDesc, ' ');
220*7dc86dfdSMatthias Ringwald           if (pBufferDesc->ReturnValue < 0) {
221*7dc86dfdSMatthias Ringwald             break;
222*7dc86dfdSMatthias Ringwald           }
223*7dc86dfdSMatthias Ringwald         }
224*7dc86dfdSMatthias Ringwald       }
225*7dc86dfdSMatthias Ringwald     }
226*7dc86dfdSMatthias Ringwald   }
227*7dc86dfdSMatthias Ringwald }
228*7dc86dfdSMatthias Ringwald 
229*7dc86dfdSMatthias Ringwald /*********************************************************************
230*7dc86dfdSMatthias Ringwald *
231*7dc86dfdSMatthias Ringwald *       _PrintInt
232*7dc86dfdSMatthias Ringwald */
233*7dc86dfdSMatthias Ringwald static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
234*7dc86dfdSMatthias Ringwald   unsigned Width;
235*7dc86dfdSMatthias Ringwald   int Number;
236*7dc86dfdSMatthias Ringwald 
237*7dc86dfdSMatthias Ringwald   Number = (v < 0) ? -v : v;
238*7dc86dfdSMatthias Ringwald 
239*7dc86dfdSMatthias Ringwald   //
240*7dc86dfdSMatthias Ringwald   // Get actual field width
241*7dc86dfdSMatthias Ringwald   //
242*7dc86dfdSMatthias Ringwald   Width = 1u;
243*7dc86dfdSMatthias Ringwald   while (Number >= (int)Base) {
244*7dc86dfdSMatthias Ringwald     Number = (Number / (int)Base);
245*7dc86dfdSMatthias Ringwald     Width++;
246*7dc86dfdSMatthias Ringwald   }
247*7dc86dfdSMatthias Ringwald   if (NumDigits > Width) {
248*7dc86dfdSMatthias Ringwald     Width = NumDigits;
249*7dc86dfdSMatthias Ringwald   }
250*7dc86dfdSMatthias Ringwald   if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
251*7dc86dfdSMatthias Ringwald     FieldWidth--;
252*7dc86dfdSMatthias Ringwald   }
253*7dc86dfdSMatthias Ringwald 
254*7dc86dfdSMatthias Ringwald   //
255*7dc86dfdSMatthias Ringwald   // Print leading spaces if necessary
256*7dc86dfdSMatthias Ringwald   //
257*7dc86dfdSMatthias Ringwald   if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
258*7dc86dfdSMatthias Ringwald     if (FieldWidth != 0u) {
259*7dc86dfdSMatthias Ringwald       while ((FieldWidth != 0u) && (Width < FieldWidth)) {
260*7dc86dfdSMatthias Ringwald         FieldWidth--;
261*7dc86dfdSMatthias Ringwald         _StoreChar(pBufferDesc, ' ');
262*7dc86dfdSMatthias Ringwald         if (pBufferDesc->ReturnValue < 0) {
263*7dc86dfdSMatthias Ringwald           break;
264*7dc86dfdSMatthias Ringwald         }
265*7dc86dfdSMatthias Ringwald       }
266*7dc86dfdSMatthias Ringwald     }
267*7dc86dfdSMatthias Ringwald   }
268*7dc86dfdSMatthias Ringwald   //
269*7dc86dfdSMatthias Ringwald   // Print sign if necessary
270*7dc86dfdSMatthias Ringwald   //
271*7dc86dfdSMatthias Ringwald   if (pBufferDesc->ReturnValue >= 0) {
272*7dc86dfdSMatthias Ringwald     if (v < 0) {
273*7dc86dfdSMatthias Ringwald       v = -v;
274*7dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, '-');
275*7dc86dfdSMatthias Ringwald     } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
276*7dc86dfdSMatthias Ringwald       _StoreChar(pBufferDesc, '+');
277*7dc86dfdSMatthias Ringwald     } else {
278*7dc86dfdSMatthias Ringwald 
279*7dc86dfdSMatthias Ringwald     }
280*7dc86dfdSMatthias Ringwald     if (pBufferDesc->ReturnValue >= 0) {
281*7dc86dfdSMatthias Ringwald       //
282*7dc86dfdSMatthias Ringwald       // Print leading zeros if necessary
283*7dc86dfdSMatthias Ringwald       //
284*7dc86dfdSMatthias Ringwald       if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
285*7dc86dfdSMatthias Ringwald         if (FieldWidth != 0u) {
286*7dc86dfdSMatthias Ringwald           while ((FieldWidth != 0u) && (Width < FieldWidth)) {
287*7dc86dfdSMatthias Ringwald             FieldWidth--;
288*7dc86dfdSMatthias Ringwald             _StoreChar(pBufferDesc, '0');
289*7dc86dfdSMatthias Ringwald             if (pBufferDesc->ReturnValue < 0) {
290*7dc86dfdSMatthias Ringwald               break;
291*7dc86dfdSMatthias Ringwald             }
292*7dc86dfdSMatthias Ringwald           }
293*7dc86dfdSMatthias Ringwald         }
294*7dc86dfdSMatthias Ringwald       }
295*7dc86dfdSMatthias Ringwald       if (pBufferDesc->ReturnValue >= 0) {
296*7dc86dfdSMatthias Ringwald         //
297*7dc86dfdSMatthias Ringwald         // Print number without sign
298*7dc86dfdSMatthias Ringwald         //
299*7dc86dfdSMatthias Ringwald         _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
300*7dc86dfdSMatthias Ringwald       }
301*7dc86dfdSMatthias Ringwald     }
302*7dc86dfdSMatthias Ringwald   }
303*7dc86dfdSMatthias Ringwald }
304*7dc86dfdSMatthias Ringwald 
305*7dc86dfdSMatthias Ringwald /*********************************************************************
306*7dc86dfdSMatthias Ringwald *
307*7dc86dfdSMatthias Ringwald *       Public code
308*7dc86dfdSMatthias Ringwald *
309*7dc86dfdSMatthias Ringwald **********************************************************************
310*7dc86dfdSMatthias Ringwald */
311*7dc86dfdSMatthias Ringwald /*********************************************************************
312*7dc86dfdSMatthias Ringwald *
313*7dc86dfdSMatthias Ringwald *       SEGGER_RTT_vprintf
314*7dc86dfdSMatthias Ringwald *
315*7dc86dfdSMatthias Ringwald *  Function description
316*7dc86dfdSMatthias Ringwald *    Stores a formatted string in SEGGER RTT control block.
317*7dc86dfdSMatthias Ringwald *    This data is read by the host.
318*7dc86dfdSMatthias Ringwald *
319*7dc86dfdSMatthias Ringwald *  Parameters
320*7dc86dfdSMatthias Ringwald *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
321*7dc86dfdSMatthias Ringwald *    sFormat      Pointer to format string
322*7dc86dfdSMatthias Ringwald *    pParamList   Pointer to the list of arguments for the format string
323*7dc86dfdSMatthias Ringwald *
324*7dc86dfdSMatthias Ringwald *  Return values
325*7dc86dfdSMatthias Ringwald *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
326*7dc86dfdSMatthias Ringwald *     < 0:  Error
327*7dc86dfdSMatthias Ringwald */
328*7dc86dfdSMatthias Ringwald int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
329*7dc86dfdSMatthias Ringwald   char c;
330*7dc86dfdSMatthias Ringwald   SEGGER_RTT_PRINTF_DESC BufferDesc;
331*7dc86dfdSMatthias Ringwald   int v;
332*7dc86dfdSMatthias Ringwald   unsigned NumDigits;
333*7dc86dfdSMatthias Ringwald   unsigned FormatFlags;
334*7dc86dfdSMatthias Ringwald   unsigned FieldWidth;
335*7dc86dfdSMatthias Ringwald   char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
336*7dc86dfdSMatthias Ringwald 
337*7dc86dfdSMatthias Ringwald   BufferDesc.pBuffer        = acBuffer;
338*7dc86dfdSMatthias Ringwald   BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
339*7dc86dfdSMatthias Ringwald   BufferDesc.Cnt            = 0u;
340*7dc86dfdSMatthias Ringwald   BufferDesc.RTTBufferIndex = BufferIndex;
341*7dc86dfdSMatthias Ringwald   BufferDesc.ReturnValue    = 0;
342*7dc86dfdSMatthias Ringwald 
343*7dc86dfdSMatthias Ringwald   do {
344*7dc86dfdSMatthias Ringwald     c = *sFormat;
345*7dc86dfdSMatthias Ringwald     sFormat++;
346*7dc86dfdSMatthias Ringwald     if (c == 0u) {
347*7dc86dfdSMatthias Ringwald       break;
348*7dc86dfdSMatthias Ringwald     }
349*7dc86dfdSMatthias Ringwald     if (c == '%') {
350*7dc86dfdSMatthias Ringwald       //
351*7dc86dfdSMatthias Ringwald       // Filter out flags
352*7dc86dfdSMatthias Ringwald       //
353*7dc86dfdSMatthias Ringwald       FormatFlags = 0u;
354*7dc86dfdSMatthias Ringwald       v = 1;
355*7dc86dfdSMatthias Ringwald       do {
356*7dc86dfdSMatthias Ringwald         c = *sFormat;
357*7dc86dfdSMatthias Ringwald         switch (c) {
358*7dc86dfdSMatthias Ringwald         case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
359*7dc86dfdSMatthias Ringwald         case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
360*7dc86dfdSMatthias Ringwald         case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
361*7dc86dfdSMatthias Ringwald         case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
362*7dc86dfdSMatthias Ringwald         default:  v = 0; break;
363*7dc86dfdSMatthias Ringwald         }
364*7dc86dfdSMatthias Ringwald       } while (v);
365*7dc86dfdSMatthias Ringwald       //
366*7dc86dfdSMatthias Ringwald       // filter out field with
367*7dc86dfdSMatthias Ringwald       //
368*7dc86dfdSMatthias Ringwald       FieldWidth = 0u;
369*7dc86dfdSMatthias Ringwald       do {
370*7dc86dfdSMatthias Ringwald         c = *sFormat;
371*7dc86dfdSMatthias Ringwald         if ((c < '0') || (c > '9')) {
372*7dc86dfdSMatthias Ringwald           break;
373*7dc86dfdSMatthias Ringwald         }
374*7dc86dfdSMatthias Ringwald         sFormat++;
375*7dc86dfdSMatthias Ringwald         FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
376*7dc86dfdSMatthias Ringwald       } while (1);
377*7dc86dfdSMatthias Ringwald 
378*7dc86dfdSMatthias Ringwald       //
379*7dc86dfdSMatthias Ringwald       // Filter out precision (number of digits to display)
380*7dc86dfdSMatthias Ringwald       //
381*7dc86dfdSMatthias Ringwald       NumDigits = 0u;
382*7dc86dfdSMatthias Ringwald       c = *sFormat;
383*7dc86dfdSMatthias Ringwald       if (c == '.') {
384*7dc86dfdSMatthias Ringwald         sFormat++;
385*7dc86dfdSMatthias Ringwald         do {
386*7dc86dfdSMatthias Ringwald           c = *sFormat;
387*7dc86dfdSMatthias Ringwald           if ((c < '0') || (c > '9')) {
388*7dc86dfdSMatthias Ringwald             break;
389*7dc86dfdSMatthias Ringwald           }
390*7dc86dfdSMatthias Ringwald           sFormat++;
391*7dc86dfdSMatthias Ringwald           NumDigits = NumDigits * 10u + ((unsigned)c - '0');
392*7dc86dfdSMatthias Ringwald         } while (1);
393*7dc86dfdSMatthias Ringwald       }
394*7dc86dfdSMatthias Ringwald       //
395*7dc86dfdSMatthias Ringwald       // Filter out length modifier
396*7dc86dfdSMatthias Ringwald       //
397*7dc86dfdSMatthias Ringwald       c = *sFormat;
398*7dc86dfdSMatthias Ringwald       do {
399*7dc86dfdSMatthias Ringwald         if ((c == 'l') || (c == 'h')) {
400*7dc86dfdSMatthias Ringwald           sFormat++;
401*7dc86dfdSMatthias Ringwald           c = *sFormat;
402*7dc86dfdSMatthias Ringwald         } else {
403*7dc86dfdSMatthias Ringwald           break;
404*7dc86dfdSMatthias Ringwald         }
405*7dc86dfdSMatthias Ringwald       } while (1);
406*7dc86dfdSMatthias Ringwald       //
407*7dc86dfdSMatthias Ringwald       // Handle specifiers
408*7dc86dfdSMatthias Ringwald       //
409*7dc86dfdSMatthias Ringwald       switch (c) {
410*7dc86dfdSMatthias Ringwald       case 'c': {
411*7dc86dfdSMatthias Ringwald         char c0;
412*7dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
413*7dc86dfdSMatthias Ringwald         c0 = (char)v;
414*7dc86dfdSMatthias Ringwald         _StoreChar(&BufferDesc, c0);
415*7dc86dfdSMatthias Ringwald         break;
416*7dc86dfdSMatthias Ringwald       }
417*7dc86dfdSMatthias Ringwald       case 'd':
418*7dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
419*7dc86dfdSMatthias Ringwald         _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
420*7dc86dfdSMatthias Ringwald         break;
421*7dc86dfdSMatthias Ringwald       case 'u':
422*7dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
423*7dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
424*7dc86dfdSMatthias Ringwald         break;
425*7dc86dfdSMatthias Ringwald       case 'x':
426*7dc86dfdSMatthias Ringwald       case 'X':
427*7dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
428*7dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
429*7dc86dfdSMatthias Ringwald         break;
430*7dc86dfdSMatthias Ringwald       case 's':
431*7dc86dfdSMatthias Ringwald         {
432*7dc86dfdSMatthias Ringwald           const char * s = va_arg(*pParamList, const char *);
433*7dc86dfdSMatthias Ringwald           do {
434*7dc86dfdSMatthias Ringwald             c = *s;
435*7dc86dfdSMatthias Ringwald             s++;
436*7dc86dfdSMatthias Ringwald             if (c == '\0') {
437*7dc86dfdSMatthias Ringwald               break;
438*7dc86dfdSMatthias Ringwald             }
439*7dc86dfdSMatthias Ringwald            _StoreChar(&BufferDesc, c);
440*7dc86dfdSMatthias Ringwald           } while (BufferDesc.ReturnValue >= 0);
441*7dc86dfdSMatthias Ringwald         }
442*7dc86dfdSMatthias Ringwald         break;
443*7dc86dfdSMatthias Ringwald       case 'p':
444*7dc86dfdSMatthias Ringwald         v = va_arg(*pParamList, int);
445*7dc86dfdSMatthias Ringwald         _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
446*7dc86dfdSMatthias Ringwald         break;
447*7dc86dfdSMatthias Ringwald       case '%':
448*7dc86dfdSMatthias Ringwald         _StoreChar(&BufferDesc, '%');
449*7dc86dfdSMatthias Ringwald         break;
450*7dc86dfdSMatthias Ringwald       default:
451*7dc86dfdSMatthias Ringwald         break;
452*7dc86dfdSMatthias Ringwald       }
453*7dc86dfdSMatthias Ringwald       sFormat++;
454*7dc86dfdSMatthias Ringwald     } else {
455*7dc86dfdSMatthias Ringwald       _StoreChar(&BufferDesc, c);
456*7dc86dfdSMatthias Ringwald     }
457*7dc86dfdSMatthias Ringwald   } while (BufferDesc.ReturnValue >= 0);
458*7dc86dfdSMatthias Ringwald 
459*7dc86dfdSMatthias Ringwald   if (BufferDesc.ReturnValue > 0) {
460*7dc86dfdSMatthias Ringwald     //
461*7dc86dfdSMatthias Ringwald     // Write remaining data, if any
462*7dc86dfdSMatthias Ringwald     //
463*7dc86dfdSMatthias Ringwald     if (BufferDesc.Cnt != 0u) {
464*7dc86dfdSMatthias Ringwald       SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
465*7dc86dfdSMatthias Ringwald     }
466*7dc86dfdSMatthias Ringwald     BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
467*7dc86dfdSMatthias Ringwald   }
468*7dc86dfdSMatthias Ringwald   return BufferDesc.ReturnValue;
469*7dc86dfdSMatthias Ringwald }
470*7dc86dfdSMatthias Ringwald 
471*7dc86dfdSMatthias Ringwald /*********************************************************************
472*7dc86dfdSMatthias Ringwald *
473*7dc86dfdSMatthias Ringwald *       SEGGER_RTT_printf
474*7dc86dfdSMatthias Ringwald *
475*7dc86dfdSMatthias Ringwald *  Function description
476*7dc86dfdSMatthias Ringwald *    Stores a formatted string in SEGGER RTT control block.
477*7dc86dfdSMatthias Ringwald *    This data is read by the host.
478*7dc86dfdSMatthias Ringwald *
479*7dc86dfdSMatthias Ringwald *  Parameters
480*7dc86dfdSMatthias Ringwald *    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
481*7dc86dfdSMatthias Ringwald *    sFormat      Pointer to format string, followed by the arguments for conversion
482*7dc86dfdSMatthias Ringwald *
483*7dc86dfdSMatthias Ringwald *  Return values
484*7dc86dfdSMatthias Ringwald *    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
485*7dc86dfdSMatthias Ringwald *     < 0:  Error
486*7dc86dfdSMatthias Ringwald *
487*7dc86dfdSMatthias Ringwald *  Notes
488*7dc86dfdSMatthias Ringwald *    (1) Conversion specifications have following syntax:
489*7dc86dfdSMatthias Ringwald *          %[flags][FieldWidth][.Precision]ConversionSpecifier
490*7dc86dfdSMatthias Ringwald *    (2) Supported flags:
491*7dc86dfdSMatthias Ringwald *          -: Left justify within the field width
492*7dc86dfdSMatthias Ringwald *          +: Always print sign extension for signed conversions
493*7dc86dfdSMatthias Ringwald *          0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
494*7dc86dfdSMatthias Ringwald *        Supported conversion specifiers:
495*7dc86dfdSMatthias Ringwald *          c: Print the argument as one char
496*7dc86dfdSMatthias Ringwald *          d: Print the argument as a signed integer
497*7dc86dfdSMatthias Ringwald *          u: Print the argument as an unsigned integer
498*7dc86dfdSMatthias Ringwald *          x: Print the argument as an hexadecimal integer
499*7dc86dfdSMatthias Ringwald *          s: Print the string pointed to by the argument
500*7dc86dfdSMatthias Ringwald *          p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
501*7dc86dfdSMatthias Ringwald */
502*7dc86dfdSMatthias Ringwald int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
503*7dc86dfdSMatthias Ringwald   int r;
504*7dc86dfdSMatthias Ringwald   va_list ParamList;
505*7dc86dfdSMatthias Ringwald 
506*7dc86dfdSMatthias Ringwald   va_start(ParamList, sFormat);
507*7dc86dfdSMatthias Ringwald   r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
508*7dc86dfdSMatthias Ringwald   va_end(ParamList);
509*7dc86dfdSMatthias Ringwald   return r;
510*7dc86dfdSMatthias Ringwald }
511*7dc86dfdSMatthias Ringwald /*************************** End of file ****************************/
512