Statistics
| Branch: | Tag: | Revision:

mongoose / examples / nRF52 / http / rtt / RTT / SEGGER_RTT_printf.c @ eaef5bd1

History | View | Annotate | Download (12.4 KB)

1
/* clang-format off */
2
/*********************************************************************
3
*              SEGGER MICROCONTROLLER GmbH & Co. KG                  *
4
*        Solutions for real time microcontroller applications        *
5
**********************************************************************
6
*                                                                    *
7
*        (c) 2014-2014 SEGGER Microcontroller GmbH & Co. KG          *
8
*                                                                    *
9
*       Internet: www.segger.com Support: support@segger.com         *
10
*                                                                    *
11
**********************************************************************
12
----------------------------------------------------------------------
13
File    : SEGGER_RTT_printf.c
14
Date    : 17 Dec 2014
15
Purpose : Replacement for printf to write formatted data via RTT
16
---------------------------END-OF-HEADER------------------------------
17
*/
18
#include "SEGGER_RTT.h"
19
#include "SEGGER_RTT_Conf.h"
20

    
21
/*********************************************************************
22
*
23
*       Defines, configurable
24
*
25
**********************************************************************
26
*/
27

    
28
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
29
  #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
30
#endif
31

    
32
#include <stdlib.h>
33
#include <stdarg.h>
34

    
35

    
36
#define FORMAT_FLAG_LEFT_JUSTIFY   (1 << 0)
37
#define FORMAT_FLAG_PAD_ZERO       (1 << 1)
38
#define FORMAT_FLAG_PRINT_SIGN     (1 << 2)
39
#define FORMAT_FLAG_ALTERNATE      (1 << 3)
40

    
41
/*********************************************************************
42
*
43
*       Types
44
*
45
**********************************************************************
46
*/
47

    
48
typedef struct {
49
  char* pBuffer;
50
  int   BufferSize;
51
  int   Cnt;
52

    
53
  int   ReturnValue;
54

    
55
  unsigned RTTBufferIndex;
56
} SEGGER_RTT_PRINTF_DESC;
57

    
58
/*********************************************************************
59
*
60
*       Function prototypes
61
*
62
**********************************************************************
63
*/
64
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
65

    
66
/*********************************************************************
67
*
68
*       Static code
69
*
70
**********************************************************************
71
*/
72
/*********************************************************************
73
*
74
*       _StoreChar
75
*/
76
static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
77
  int Cnt;
78

    
79
  Cnt = p->Cnt;
80
  if ((Cnt + 1) <= p->BufferSize) {
81
    *(p->pBuffer + Cnt) = c;
82
    p->Cnt = Cnt + 1;
83
    p->ReturnValue++;
84
  }
85
  //
86
  // Write part of string, when the buffer is full
87
  //
88
  if (p->Cnt == p->BufferSize) {
89
    if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
90
      p->ReturnValue = -1;
91
    } else {
92
      p->Cnt = 0;
93
    }
94
  }
95
}
96

    
97
/*********************************************************************
98
*
99
*       _PrintUnsigned
100
*/
101
static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, int NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
102
  static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
103
  unsigned Div;
104
  unsigned Digit = 1;
105
  unsigned Number;
106
  unsigned Width;
107
  char c;
108

    
109
  Number = v;
110

    
111
  //
112
  // Get actual field width
113
  //
114
  Width = 1;
115
  while (Number >= Base) {
116
    Number = (Number / Base);
117
    Width++;
118
  }
119
  if ((unsigned)NumDigits > Width) {
120
    Width = NumDigits;
121
  }
122
  //
123
  // Print leading chars if necessary
124
  //
125
  if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) {
126
    if (FieldWidth != 0) {
127
      if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0)) {
128
        c = '0';
129
      } else {
130
        c = ' ';
131
      }
132
      while ((FieldWidth != 0) && (Width < FieldWidth--)) {
133
        _StoreChar(pBufferDesc, c);
134
        if (pBufferDesc->ReturnValue < 0) {
135
          return;
136
        }
137
      }
138
    }
139
  }
140
  //
141
  // Count how many digits are required by precision
142
  //
143
  while (((v / Digit) >= Base) | (NumDigits-- > 1)) {
144
    Digit *= Base;
145
  }
146
  //
147
  // Output digits
148
  //
149
  do {
150
    Div = v / Digit;
151
    v -= Div * Digit;
152
    _StoreChar(pBufferDesc, _aV2C[Div]);
153
    if (pBufferDesc->ReturnValue < 0) {
154
      break;
155
    }
156
    Digit /= Base;
157
  } while (Digit);
158
  //
159
  // Print trailing spaces if necessary
160
  //
161
  if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
162
    if (FieldWidth != 0) {
163
      while ((FieldWidth != 0) && (Width < FieldWidth--)) {
164
        _StoreChar(pBufferDesc, ' ');
165
        if (pBufferDesc->ReturnValue < 0) {
166
          return;
167
        }
168
      }
169
    }
170
  }
171
}
172

    
173
/*********************************************************************
174
*
175
*       _PrintInt
176
*/
177
static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
178
  unsigned Width;
179
  unsigned Number;
180

    
181
  Number = (v < 0) ? -v : v;
182

    
183
  //
184
  // Get actual field width
185
  //
186
  Width = 1;
187
  while (Number >= Base) {
188
    Number = (Number / Base);
189
    Width++;
190
  }
191
  if (NumDigits > Width) {
192
    Width = NumDigits;
193
  }
194
  if ((FieldWidth > 0) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
195
    FieldWidth--;
196
  }
197

    
198
  //
199
  // Print leading spaces if necessary
200
  //
201
  if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0) || (NumDigits != 0)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0)) {
202
    if (FieldWidth != 0) {
203
      while ((FieldWidth != 0) && (Width < FieldWidth--)) {
204
        _StoreChar(pBufferDesc, ' ');
205
        if (pBufferDesc->ReturnValue < 0) {
206
          return;
207
        }
208
      }
209
    }
210
  }
211
  //
212
  // Print sign if necessary
213
  //
214
  if (v < 0) {
215
    v = -v;
216
    _StoreChar(pBufferDesc, '-');
217
    if (pBufferDesc->ReturnValue < 0) {
218
      return;
219
    }
220
  } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
221
    _StoreChar(pBufferDesc, '+');
222
    if (pBufferDesc->ReturnValue < 0) {
223
      return;
224
    }
225
  }
226
  //
227
  // Print leading zeros if necessary
228
  //
229
  if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0) && (NumDigits == 0)) {
230
    if (FieldWidth != 0) {
231
      while ((FieldWidth != 0) && (Width < FieldWidth--)) {
232
        _StoreChar(pBufferDesc, '0');
233
        if (pBufferDesc->ReturnValue < 0) {
234
          return;
235
        }
236
      }
237
    }
238
  }
239

    
240
  //
241
  // Print number without sign
242
  //
243
  _PrintUnsigned(pBufferDesc, v, Base, NumDigits, FieldWidth, FormatFlags);
244
}
245

    
246
/*********************************************************************
247
*
248
*       Public code
249
*
250
**********************************************************************
251
*/
252
/*********************************************************************
253
*
254
*       SEGGER_RTT_vprintf
255
*
256
*  Function description
257
*    Stores a formatted string in SEGGER RTT control block.
258
*    This data is read by the host.
259
*
260
*  Parameters
261
*    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
262
*    sFormat      Pointer to format string
263
*    pParamList   Pointer to the list of arguments for the format string
264
*
265
*  Return values
266
*    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
267
*     < 0:  Error
268
*/
269
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
270
  char c;
271
  SEGGER_RTT_PRINTF_DESC BufferDesc;
272
  int v;
273
  unsigned NumDigits;
274
  unsigned FormatFlags;
275
  unsigned FieldWidth;
276
  char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
277

    
278
  BufferDesc.pBuffer        = acBuffer;
279
  BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
280
  BufferDesc.Cnt            = 0;
281
  BufferDesc.RTTBufferIndex = BufferIndex;
282
  BufferDesc.ReturnValue    = 0;
283

    
284
  do {
285
    c = *sFormat++;
286
    if (c == 0) {
287
      break;
288
    }
289
    if (c == '%') {
290
      //
291
      // Filter out flags
292
      //
293
      FormatFlags = 0;
294
      do {
295
        c = *sFormat;
296
        switch (c) {
297
        case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
298
        case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
299
        case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
300
        case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
301
        default:  goto FilterFieldWidth;                   break;
302
        }
303
      } while (1);
304
      //
305
      // filter out field with
306
      //
307
FilterFieldWidth:
308
      FieldWidth = 0;
309
      do {
310
        c = *sFormat;
311
        if (c < '0' || c > '9') {
312
          break;
313
        }
314
        sFormat++;
315
        FieldWidth = FieldWidth * 10 + (c - '0');
316
      } while (1);
317

    
318
      //
319
      // Filter out precision (number of digits to display)
320
      //
321
      NumDigits = 0;
322
      c = *sFormat;
323
      if (c == '.') {
324
        sFormat++;
325
        do {
326
          c = *sFormat;
327
          if (c < '0' || c > '9') {
328
            break;
329
          }
330
          sFormat++;
331
          NumDigits = NumDigits * 10 + (c - '0');
332
        } while (1);
333
      }
334
      //
335
      // Filter out length modifier
336
      //
337
      c = *sFormat;
338
      do {
339
        if (c == 'l' || c == 'h') {
340
          c = *sFormat++;
341
          continue;
342
        }
343
        break;
344
      } while (1);
345
      //
346
      // Handle specifiers
347
      //
348
      switch (c) {
349
      case 'c': {
350
        char c0;
351
        v = va_arg(*pParamList, int);
352
        c0 = (char)v;
353
        _StoreChar(&BufferDesc, c0);
354
        break;
355
      }
356
      case 'd':
357
        v = va_arg(*pParamList, int);
358
        _PrintInt(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
359
        break;
360
      case 'u':
361
        v = va_arg(*pParamList, int);
362
        _PrintUnsigned(&BufferDesc, v, 10, NumDigits, FieldWidth, FormatFlags);
363
        break;
364
      case 'x':
365
      case 'X':
366
        v = va_arg(*pParamList, int);
367
        _PrintUnsigned(&BufferDesc, v, 16, NumDigits, FieldWidth, FormatFlags);
368
        break;
369
      case 's':
370
        {
371
          const char * s = va_arg(*pParamList, const char *);
372
          do {
373
            c = *s++;
374
            if (c == 0) {
375
              break;
376
            }
377
           _StoreChar(&BufferDesc, c);
378
          } while (BufferDesc.ReturnValue >= 0);
379
        }
380
        break;
381
      case 'p':
382
        v = va_arg(*pParamList, int);
383
        _PrintUnsigned(&BufferDesc, v, 16, 8, 8, 0);
384
        break;
385
      case '%':
386
        _StoreChar(&BufferDesc, '%');
387
        break;
388
      }
389
      sFormat++;
390
    } else {
391
      _StoreChar(&BufferDesc, c);
392
    }
393
  } while (BufferDesc.ReturnValue >= 0);
394

    
395
  if (BufferDesc.ReturnValue > 0) {
396
    //
397
    // Write remaining data, if any
398
    //
399
    if (BufferDesc.Cnt != 0) {
400
      SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
401
    }
402
    BufferDesc.ReturnValue += BufferDesc.Cnt;
403
  }
404
  return BufferDesc.ReturnValue;
405
}
406

    
407
/*********************************************************************
408
*
409
*       SEGGER_RTT_printf
410
*
411
*  Function description
412
*    Stores a formatted string in SEGGER RTT control block.
413
*    This data is read by the host.
414
*
415
*  Parameters
416
*    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
417
*    sFormat      Pointer to format string, followed by the arguments for conversion
418
*
419
*  Return values
420
*    >= 0:  Number of bytes which have been stored in the "Up"-buffer.
421
*     < 0:  Error
422
*
423
*  Notes
424
*    (1) Conversion specifications have following syntax:
425
*          %[flags][FieldWidth][.Precision]ConversionSpecifier
426
*    (2) Supported flags:
427
*          -: Left justify within the field width
428
*          +: Always print sign extension for signed conversions
429
*          0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
430
*        Supported conversion specifiers:
431
*          c: Print the argument as one char
432
*          d: Print the argument as a signed integer
433
*          u: Print the argument as an unsigned integer
434
*          x: Print the argument as an hexadecimal integer
435
*          s: Print the string pointed to by the argument
436
*          p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
437
*/
438
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
439
  va_list ParamList;
440

    
441
  va_start(ParamList, sFormat);
442
  return SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
443
}
444
/*************************** End of file ****************************/