SEGGER_RTT_printf.c 16 KB

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