nrf_fprintf_format.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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.14d *
  56. * *
  57. *********************************************************************/
  58. #include "sdk_common.h"
  59. #if NRF_MODULE_ENABLED(NRF_FPRINTF)
  60. #include <stdarg.h>
  61. #include "nrf_assert.h"
  62. #include "nrf_fprintf.h"
  63. #include "nrf_fprintf_format.h"
  64. #define NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
  65. #define NRF_CLI_FORMAT_FLAG_PAD_ZERO (1u << 1)
  66. #define NRF_CLI_FORMAT_FLAG_PRINT_SIGN (1u << 2)
  67. static void buffer_add(nrf_fprintf_ctx_t * const p_ctx, char c)
  68. {
  69. #if NRF_MODULE_ENABLED(NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF)
  70. if (c == '\n')
  71. {
  72. buffer_add(p_ctx, '\r');
  73. }
  74. #endif
  75. p_ctx->p_io_buffer[p_ctx->io_buffer_cnt++] = c;
  76. if (p_ctx->io_buffer_cnt >= p_ctx->io_buffer_size)
  77. {
  78. nrf_fprintf_buffer_flush(p_ctx);
  79. }
  80. }
  81. static void string_print(nrf_fprintf_ctx_t * const p_ctx,
  82. char const * p_str,
  83. uint32_t FieldWidth,
  84. uint32_t FormatFlags)
  85. {
  86. uint32_t Width = 0;
  87. char c;
  88. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
  89. {
  90. while ((c = *p_str) != '\0')
  91. {
  92. p_str++;
  93. Width++;
  94. buffer_add(p_ctx, c);
  95. }
  96. while ((FieldWidth > Width) && (FieldWidth > 0))
  97. {
  98. FieldWidth--;
  99. buffer_add(p_ctx, ' ');
  100. }
  101. }
  102. else
  103. {
  104. if (p_str != 0)
  105. {
  106. Width = strlen(p_str);
  107. }
  108. while ((FieldWidth > Width) && (FieldWidth > 0))
  109. {
  110. FieldWidth--;
  111. buffer_add(p_ctx, ' ');
  112. }
  113. while ((c = *p_str) != '\0')
  114. {
  115. p_str++;
  116. Width++;
  117. buffer_add(p_ctx, c);
  118. }
  119. }
  120. }
  121. static void unsigned_print(nrf_fprintf_ctx_t * const p_ctx,
  122. uint32_t v,
  123. uint32_t Base,
  124. uint32_t NumDigits,
  125. uint32_t FieldWidth,
  126. uint32_t FormatFlags)
  127. {
  128. static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  129. 'A', 'B', 'C', 'D', 'E', 'F' };
  130. uint32_t Div;
  131. uint32_t Value;
  132. uint32_t Width;
  133. char c;
  134. Value = v;
  135. //
  136. // Get actual field width
  137. //
  138. Width = 1u;
  139. while (Value >= Base)
  140. {
  141. Value = (Value / Base);
  142. Width++;
  143. }
  144. if (NumDigits > Width)
  145. {
  146. Width = NumDigits;
  147. }
  148. //
  149. // Print leading chars if necessary
  150. //
  151. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u)
  152. {
  153. if (FieldWidth != 0u)
  154. {
  155. if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
  156. (NumDigits == 0u))
  157. {
  158. c = '0';
  159. }
  160. else
  161. {
  162. c = ' ';
  163. }
  164. while ((FieldWidth != 0u) && (Width < FieldWidth))
  165. {
  166. FieldWidth--;
  167. buffer_add(p_ctx, c);
  168. }
  169. }
  170. }
  171. Value = 1;
  172. /*
  173. * Compute Digit.
  174. * Loop until Digit has the value of the highest digit required.
  175. * Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
  176. */
  177. while (1)
  178. {
  179. /* User specified a min number of digits to print? => Make sure we loop at least that
  180. * often, before checking anything else (> 1 check avoids problems with NumDigits
  181. * being signed / unsigned)
  182. */
  183. if (NumDigits > 1u)
  184. {
  185. NumDigits--;
  186. }
  187. else
  188. {
  189. Div = v / Value;
  190. // Is our divider big enough to extract the highest digit from value? => Done
  191. if (Div < Base)
  192. {
  193. break;
  194. }
  195. }
  196. Value *= Base;
  197. }
  198. //
  199. // Output digits
  200. //
  201. do
  202. {
  203. Div = v / Value;
  204. v -= Div * Value;
  205. buffer_add(p_ctx, _aV2C[Div]);
  206. Value /= Base;
  207. } while (Value);
  208. //
  209. // Print trailing spaces if necessary
  210. //
  211. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
  212. {
  213. if (FieldWidth != 0u)
  214. {
  215. while ((FieldWidth != 0u) && (Width < FieldWidth))
  216. {
  217. FieldWidth--;
  218. buffer_add(p_ctx, ' ');
  219. }
  220. }
  221. }
  222. }
  223. static void int_print(nrf_fprintf_ctx_t * const p_ctx,
  224. int32_t v,
  225. uint32_t Base,
  226. uint32_t NumDigits,
  227. uint32_t FieldWidth,
  228. uint32_t FormatFlags)
  229. {
  230. uint32_t Width;
  231. int32_t Number;
  232. Number = (v < 0) ? -v : v;
  233. //
  234. // Get actual field width
  235. //
  236. Width = 1u;
  237. while (Number >= (int32_t)Base)
  238. {
  239. Number = (Number / (int32_t)Base);
  240. Width++;
  241. }
  242. if (NumDigits > Width)
  243. {
  244. Width = NumDigits;
  245. }
  246. if ((FieldWidth > 0u) && ((v < 0) ||
  247. ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)))
  248. {
  249. FieldWidth--;
  250. }
  251. //
  252. // Print leading spaces if necessary
  253. //
  254. if ((((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) &&
  255. ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u))
  256. {
  257. if (FieldWidth != 0u)
  258. {
  259. while ((FieldWidth != 0u) && (Width < FieldWidth))
  260. {
  261. FieldWidth--;
  262. buffer_add(p_ctx, ' ');
  263. }
  264. }
  265. }
  266. //
  267. // Print sign if necessary
  268. //
  269. if (v < 0)
  270. {
  271. v = -v;
  272. buffer_add(p_ctx, '-');
  273. }
  274. else if ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)
  275. {
  276. buffer_add(p_ctx, '+');
  277. }
  278. else
  279. {
  280. /* do nothing */
  281. }
  282. //
  283. // Print leading zeros if necessary
  284. //
  285. if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
  286. ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u))
  287. {
  288. if (FieldWidth != 0u)
  289. {
  290. while ((FieldWidth != 0u) && (Width < FieldWidth))
  291. {
  292. FieldWidth--;
  293. buffer_add(p_ctx, '0');
  294. }
  295. }
  296. }
  297. //
  298. // Print number without sign
  299. //
  300. unsigned_print(p_ctx, (uint32_t)v, Base, NumDigits, FieldWidth, FormatFlags);
  301. }
  302. void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
  303. char const * p_fmt,
  304. va_list * p_args)
  305. {
  306. ASSERT(p_ctx != NULL);
  307. ASSERT(p_ctx->fwrite != NULL);
  308. ASSERT(p_ctx->p_io_buffer != NULL);
  309. ASSERT(p_ctx->io_buffer_size > 0);
  310. if (p_fmt == NULL)
  311. {
  312. return;
  313. }
  314. char c;
  315. int32_t v;
  316. uint32_t NumDigits;
  317. uint32_t FormatFlags;
  318. uint32_t FieldWidth;
  319. do
  320. {
  321. c = *p_fmt;
  322. p_fmt++;
  323. if (c == 0u)
  324. {
  325. break;
  326. }
  327. if (c == '%')
  328. {
  329. //
  330. // Filter out flags
  331. //
  332. FormatFlags = 0u;
  333. v = 1;
  334. do
  335. {
  336. c = *p_fmt;
  337. switch (c)
  338. {
  339. case '-':
  340. FormatFlags |= NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY;
  341. p_fmt++;
  342. break;
  343. case '0':
  344. FormatFlags |= NRF_CLI_FORMAT_FLAG_PAD_ZERO;
  345. p_fmt++;
  346. break;
  347. case '+':
  348. FormatFlags |= NRF_CLI_FORMAT_FLAG_PRINT_SIGN;
  349. p_fmt++;
  350. break;
  351. default:
  352. v = 0;
  353. break;
  354. }
  355. } while (v);
  356. //
  357. // filter out field width
  358. //
  359. FieldWidth = 0u;
  360. do
  361. {
  362. if (c == '*')
  363. {
  364. /*lint -save -e64 -e56*/
  365. FieldWidth += va_arg(*p_args, unsigned);
  366. /*lint -restore*/
  367. p_fmt++;
  368. break;
  369. }
  370. c = *p_fmt;
  371. if ((c < '0') || (c > '9'))
  372. {
  373. break;
  374. }
  375. p_fmt++;
  376. FieldWidth = (FieldWidth * 10u) + (c - '0');
  377. } while (1);
  378. //
  379. // Filter out precision (number of digits to display)
  380. //
  381. NumDigits = 0u;
  382. c = *p_fmt;
  383. if (c == '.')
  384. {
  385. p_fmt++;
  386. do
  387. {
  388. c = *p_fmt;
  389. if ((c < '0') || (c > '9'))
  390. {
  391. break;
  392. }
  393. p_fmt++;
  394. NumDigits = NumDigits * 10u + (c - '0');
  395. } while (1);
  396. }
  397. //
  398. // Filter out length modifier
  399. //
  400. c = *p_fmt;
  401. do
  402. {
  403. if ((c == 'l') || (c == 'h'))
  404. {
  405. p_fmt++;
  406. c = *p_fmt;
  407. }
  408. else
  409. {
  410. break;
  411. }
  412. } while (1);
  413. //
  414. // Handle specifiers
  415. //
  416. /*lint -save -e64*/
  417. switch (c)
  418. {
  419. case 'c':
  420. {
  421. char c0;
  422. v = va_arg(*p_args, int32_t);
  423. c0 = (char)v;
  424. buffer_add(p_ctx, c0);
  425. break;
  426. }
  427. case 'd':
  428. case 'i':
  429. v = va_arg(*p_args, int32_t);
  430. int_print(p_ctx,
  431. v,
  432. 10u,
  433. NumDigits,
  434. FieldWidth,
  435. FormatFlags);
  436. break;
  437. case 'u':
  438. v = va_arg(*p_args, int32_t);
  439. unsigned_print(p_ctx,
  440. (uint32_t)v,
  441. 10u,
  442. NumDigits,
  443. FieldWidth,
  444. FormatFlags);
  445. break;
  446. case 'x':
  447. case 'X':
  448. v = va_arg(*p_args, int32_t);
  449. unsigned_print(p_ctx,
  450. (uint32_t)v,
  451. 16u,
  452. NumDigits,
  453. FieldWidth,
  454. FormatFlags);
  455. break;
  456. case 's':
  457. {
  458. char const * p_s = va_arg(*p_args, const char *);
  459. string_print(p_ctx, p_s, FieldWidth, FormatFlags);
  460. break;
  461. }
  462. case 'p':
  463. v = va_arg(*p_args, int32_t);
  464. buffer_add(p_ctx, '0');
  465. buffer_add(p_ctx, 'x');
  466. unsigned_print(p_ctx, (uint32_t)v, 16u, 8u, 8u, 0);
  467. break;
  468. case '%':
  469. buffer_add(p_ctx, '%');
  470. break;
  471. default:
  472. break;
  473. }
  474. /*lint -restore*/
  475. p_fmt++;
  476. }
  477. else
  478. {
  479. buffer_add(p_ctx, c);
  480. }
  481. } while (*p_fmt != '\0');
  482. if (p_ctx->auto_flush)
  483. {
  484. nrf_fprintf_buffer_flush(p_ctx);
  485. }
  486. }
  487. #endif // NRF_MODULE_ENABLED(NRF_FPRINTF)