1 /*********************************************************************
\r
2 * SEGGER MICROCONTROLLER GmbH & Co. KG *
\r
3 * Solutions for real time microcontroller applications *
\r
4 **********************************************************************
\r
6 * (c) 2014-2014 SEGGER Microcontroller GmbH & Co. KG *
\r
8 * Internet: www.segger.com Support: support@segger.com *
\r
10 **********************************************************************
\r
11 ----------------------------------------------------------------------
\r
12 File : SEGGER_RTT_printf.c
\r
14 Purpose : Replacement for printf to write formatted data via RTT
\r
15 ---------------------------END-OF-HEADER------------------------------
\r
17 #include "SEGGER_RTT.h"
\r
18 #include "SEGGER_RTT_Conf.h"
\r
20 /*********************************************************************
\r
22 * Defines, configurable
\r
24 **********************************************************************
\r
27 #ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
\r
28 #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
\r
35 #define FORMAT_FLAG_LEFT_JUSTIFY (1 << 0)
\r
36 #define FORMAT_FLAG_PAD_ZERO (1 << 1)
\r
37 #define FORMAT_FLAG_PRINT_SIGN (1 << 2)
\r
38 #define FORMAT_FLAG_ALTERNATE (1 << 3)
\r
40 /*********************************************************************
\r
44 **********************************************************************
\r
54 unsigned RTTBufferIndex;
\r
55 } SEGGER_RTT_PRINTF_DESC;
\r
57 /*********************************************************************
\r
59 * Function prototypes
\r
61 **********************************************************************
\r
63 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
\r
65 /*********************************************************************
\r
69 **********************************************************************
\r
71 /*********************************************************************
\r
75 static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
\r
79 if ((Cnt + 1) <= p->BufferSize) {
\r
80 *(p->pBuffer + Cnt) = c;
\r
85 // Write part of string, when the buffer is full
\r
87 if (p->Cnt == p->BufferSize) {
\r
88 if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
\r
89 p->ReturnValue = -1;
\r
96 /*********************************************************************
\r
100 static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, int NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
\r
101 static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
\r
103 unsigned Digit = 1;
\r
111 // Get actual field width
\r
114 while (Number >= Base) {
\r
115 Number = (Number / Base);
\r
118 if ((unsigned)NumDigits > Width) {
\r
122 // Print leading chars if necessary
\r
124 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) {
\r
125 if (FieldWidth != 0) {
\r
126 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0)) {
\r
131 while ((FieldWidth != 0) && (Width < FieldWidth--)) {
\r
132 _StoreChar(pBufferDesc, c);
\r
133 if (pBufferDesc->ReturnValue < 0) {
\r
140 // Count how many digits are required by precision
\r
142 while (((v / Digit) >= Base) | (NumDigits-- > 1)) {
\r
151 _StoreChar(pBufferDesc, _aV2C[Div]);
\r
152 if (pBufferDesc->ReturnValue < 0) {
\r
158 // Print trailing spaces if necessary
\r
160 if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
\r
161 if (FieldWidth != 0) {
\r
162 while ((FieldWidth != 0) && (Width < FieldWidth--)) {
\r
163 _StoreChar(pBufferDesc, ' ');
\r
164 if (pBufferDesc->ReturnValue < 0) {
\r
172 /*********************************************************************
\r
176 static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
\r
180 Number = (v < 0) ? -v : v;
\r
183 // Get actual field width
\r
186 while (Number >= Base) {
\r
187 Number = (Number / Base);
\r
190 if (NumDigits > Width) {
\r
193 if ((FieldWidth > 0) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
\r
198 // Print leading spaces if necessary
\r
200 if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0) || (NumDigits != 0)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0)) {
\r
201 if (FieldWidth != 0) {
\r
202 while ((FieldWidth != 0) && (Width < FieldWidth--)) {
\r
203 _StoreChar(pBufferDesc, ' ');
\r
204 if (pBufferDesc->ReturnValue < 0) {
\r
211 // Print sign if necessary
\r
215 _StoreChar(pBufferDesc, '-');
\r
216 if (pBufferDesc->ReturnValue < 0) {
\r
219 } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
\r
220 _StoreChar(pBufferDesc, '+');
\r
221 if (pBufferDesc->ReturnValue < 0) {
\r
226 // Print leading zeros if necessary
\r
228 if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) && (NumDigits == 0)) {
\r
229 if (FieldWidth != 0) {
\r
230 while ((FieldWidth != 0) && (Width < FieldWidth--)) {
\r
231 _StoreChar(pBufferDesc, '0');
\r
232 if (pBufferDesc->ReturnValue < 0) {
\r
240 // Print number without sign
\r
242 _PrintUnsigned(pBufferDesc, v, Base, NumDigits, FieldWidth, FormatFlags);
\r
245 /*********************************************************************
\r
249 **********************************************************************
\r
251 /*********************************************************************
\r
253 * SEGGER_RTT_vprintf
\r
255 * Function description
\r
256 * Stores a formatted string in SEGGER RTT control block.
\r
257 * This data is read by the host.
\r
260 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
\r
261 * sFormat Pointer to format string
\r
262 * pParamList Pointer to the list of arguments for the format string
\r
265 * >= 0: Number of bytes which have been stored in the "Up"-buffer.
\r
268 int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
\r
270 SEGGER_RTT_PRINTF_DESC BufferDesc;
\r
272 unsigned NumDigits;
\r
273 unsigned FormatFlags;
\r
274 unsigned FieldWidth;
\r
275 char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
\r
277 BufferDesc.pBuffer = acBuffer;
\r
278 BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
\r
279 BufferDesc.Cnt = 0;
\r
280 BufferDesc.RTTBufferIndex = BufferIndex;
\r
281 BufferDesc.ReturnValue = 0;
\r
290 // Filter out flags
\r
296 case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
\r
297 case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
\r
298 case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
\r
299 case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
\r
300 default: goto FilterFieldWidth; break;
\r
304 // filter out field with
\r
310 if (c < '0' || c > '9') {
\r
314 FieldWidth = FieldWidth * 10 + (c - '0');
\r
318 // Filter out precision (number of digits to display)
\r
326 if (c < '0' || c > '9') {
\r
330 NumDigits = NumDigits * 10 + (c - '0');
\r
334 // Filter out length modifier
\r
338 if (c == 'l' || c == 'h') {
\r
345 // Handle specifiers
\r
350 v = va_arg(*pParamList, int);
\r
352 _StoreChar(&BufferDesc, c0);
\r
356 v = va_arg(*pParamList, int);
\r
357 _PrintInt(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
\r
360 v = va_arg(*pParamList, int);
\r
361 _PrintUnsigned(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
\r
365 v = va_arg(*pParamList, int);
\r
366 _PrintUnsigned(&BufferDesc, v, 16, NumDigits, FieldWidth, FormatFlags);
\r
370 const char * s = va_arg(*pParamList, const char *);
\r
376 _StoreChar(&BufferDesc, c);
\r
377 } while (BufferDesc.ReturnValue >= 0);
\r
381 v = va_arg(*pParamList, int);
\r
382 _PrintUnsigned(&BufferDesc, v, 16, 8, 8, 0);
\r
385 _StoreChar(&BufferDesc, '%');
\r
390 _StoreChar(&BufferDesc, c);
\r
392 } while (BufferDesc.ReturnValue >= 0);
\r
394 if (BufferDesc.ReturnValue > 0) {
\r
396 // Write remaining data, if any
\r
398 if (BufferDesc.Cnt != 0) {
\r
399 SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
\r
401 BufferDesc.ReturnValue += BufferDesc.Cnt;
\r
403 return BufferDesc.ReturnValue;
\r
406 /*********************************************************************
\r
408 * SEGGER_RTT_printf
\r
410 * Function description
\r
411 * Stores a formatted string in SEGGER RTT control block.
\r
412 * This data is read by the host.
\r
415 * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
\r
416 * sFormat Pointer to format string, followed by the arguments for conversion
\r
419 * >= 0: Number of bytes which have been stored in the "Up"-buffer.
\r
423 * (1) Conversion specifications have following syntax:
\r
424 * %[flags][FieldWidth][.Precision]ConversionSpecifier
\r
425 * (2) Supported flags:
\r
426 * -: Left justify within the field width
\r
427 * +: Always print sign extension for signed conversions
\r
428 * 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
\r
429 * Supported conversion specifiers:
\r
430 * c: Print the argument as one char
\r
431 * d: Print the argument as a signed integer
\r
432 * u: Print the argument as an unsigned integer
\r
433 * x: Print the argument as an hexadecimal integer
\r
434 * s: Print the string pointed to by the argument
\r
435 * p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
\r
437 int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
\r
440 va_start(ParamList, sFormat);
\r
441 return SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
\r
443 /*************************** End of file ****************************/
\r