You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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