SEGGER_RTT_printf.c 15 KB

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