SEGGER_RTT_printf.c 15 KB

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