SEGGER_RTT_printf.c 15 KB

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