blob: a6208e4c8c35a732729d63812565f9ff5aea3636 [file] [log] [blame]
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +08001/*
yang.lib06e0a82022-01-10 17:35:09 +08002 * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +08003 *
yang.lib06e0a82022-01-10 17:35:09 +08004 * SPDX-License-Identifier: MIT
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +08005 */
Xiaohu.Huang448314d2021-12-31 17:12:48 +08006#include "aml_printf.h"
xiaohu.huang9169c492022-11-18 16:30:06 +08007#include "aml_strnlen.h"
8#include "aml_isdigit.h"
9#include <stdarg.h>
10#include <stddef.h>
Xiaohu.Huang448314d2021-12-31 17:12:48 +080011#if (1 == CONFIG_ARM64)
xiaohu.huang1fd6f112022-05-24 11:02:05 +080012#include "serial.h"
Xiaohu.Huang448314d2021-12-31 17:12:48 +080013#else
xiaohu.huang1fd6f112022-05-24 11:02:05 +080014#include "uart.h"
Xiaohu.Huang448314d2021-12-31 17:12:48 +080015#endif
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080016
xiaohu.huang9169c492022-11-18 16:30:06 +080017#define HAS_FLOAT 1
18#define MAX_BUFFER_LEN 512
19static char printbuffer[MAX_BUFFER_LEN];
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080020
xiaohu.huang9169c492022-11-18 16:30:06 +080021#define ZEROPAD (1 << 0) /* Pad with zero */
22#define SIGN (1 << 1) /* Unsigned/signed long */
23#define PLUS (1 << 2) /* Show plus */
24#define SPACE (1 << 3) /* Spacer */
25#define LEFT (1 << 4) /* Left justified */
26#define HEX_PREP (1 << 5) /* 0x */
27#define UPPERCASE (1 << 6) /* 'ABCDEF' */
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080028
xiaohu.huang9169c492022-11-18 16:30:06 +080029static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
30static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
31
32static int skip_atoi(const char **s)
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080033{
xiaohu.huang9169c492022-11-18 16:30:06 +080034 int i = 0;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080035
xiaohu.huang9169c492022-11-18 16:30:06 +080036 while (isdigit(**s))
37 i = i * 10 + *((*s)++) - '0';
38
39 return i;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080040}
41
xiaohu.huang9169c492022-11-18 16:30:06 +080042static char *number(char *str, long num, int base, int size, int precision, int type)
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080043{
xiaohu.huang9169c492022-11-18 16:30:06 +080044 char c, sign, tmp[66];
45 char *dig = digits;
46 int i;
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080047
xiaohu.huang9169c492022-11-18 16:30:06 +080048 if (type & UPPERCASE)
49 dig = upper_digits;
50 if (type & LEFT)
51 type &= ~ZEROPAD;
52 if (base < 2 || base > 36)
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080053 return 0;
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080054
xiaohu.huang9169c492022-11-18 16:30:06 +080055 c = (type & ZEROPAD) ? '0' : ' ';
56 sign = 0;
57 if (type & SIGN) {
58 if (num < 0) {
59 sign = '-';
60 num = -num;
61 size--;
62 } else if (type & PLUS) {
63 sign = '+';
64 size--;
65 } else if (type & SPACE) {
66 sign = ' ';
67 size--;
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080068 }
69 }
xiaohu.huang9169c492022-11-18 16:30:06 +080070
71 if (type & HEX_PREP) {
72 if (base == 16)
73 size -= 2;
74 else if (base == 8)
75 size--;
76 }
77
78 i = 0;
79
80 if (num == 0)
81 tmp[i++] = '0';
82 else {
83 while (num != 0) {
84 tmp[i++] = dig[((unsigned long)num) % (unsigned int)base];
85 num = ((unsigned long)num) / (unsigned int)base;
86 }
87 }
88
89 if (i > precision)
90 precision = i;
91 size -= precision;
92 if (!(type & (ZEROPAD | LEFT)))
93 while (size-- > 0)
94 *str++ = ' ';
95 if (sign)
96 *str++ = sign;
97
98 if (type & HEX_PREP) {
99 if (base == 8)
100 *str++ = '0';
101 else if (base == 16) {
102 *str++ = '0';
103 *str++ = digits[33];
104 }
105 }
106
107 if (!(type & LEFT))
108 while (size-- > 0)
109 *str++ = c;
110 while (i < precision--)
111 *str++ = '0';
112 while (i-- > 0)
113 *str++ = tmp[i];
114 while (size-- > 0)
115 *str++ = ' ';
116
117 return str;
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +0800118}
119
xiaohu.huang9169c492022-11-18 16:30:06 +0800120static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800121{
xiaohu.huang9169c492022-11-18 16:30:06 +0800122 char tmp[24];
123 char *dig = digits;
124 int i, len;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800125
xiaohu.huang9169c492022-11-18 16:30:06 +0800126 if (type & UPPERCASE)
127 dig = upper_digits;
128 len = 0;
129 for (i = 0; i < 6; i++) {
130 if (i != 0)
131 tmp[len++] = ':';
132 tmp[len++] = dig[addr[i] >> 4];
133 tmp[len++] = dig[addr[i] & 0x0F];
134 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800135
xiaohu.huang9169c492022-11-18 16:30:06 +0800136 if (!(type & LEFT))
137 while (len < size--)
138 *str++ = ' ';
139 for (i = 0; i < len; ++i)
140 *str++ = tmp[i];
141 while (len < size--)
142 *str++ = ' ';
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800143
xiaohu.huang9169c492022-11-18 16:30:06 +0800144 return str;
145}
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800146
xiaohu.huang9169c492022-11-18 16:30:06 +0800147static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
148{
149 char tmp[24];
150 int i, n, len;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800151
xiaohu.huang9169c492022-11-18 16:30:06 +0800152 len = 0;
153 for (i = 0; i < 4; i++) {
154 if (i != 0)
155 tmp[len++] = '.';
156 n = addr[i];
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800157
xiaohu.huang9169c492022-11-18 16:30:06 +0800158 if (n == 0)
159 tmp[len++] = digits[0];
160 else {
161 if (n >= 100) {
162 tmp[len++] = digits[n / 100];
163 n = n % 100;
164 tmp[len++] = digits[n / 10];
165 n = n % 10;
166 } else if (n >= 10) {
167 tmp[len++] = digits[n / 10];
168 n = n % 10;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800169 }
170
xiaohu.huang9169c492022-11-18 16:30:06 +0800171 tmp[len++] = digits[n];
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800172 }
173 }
174
xiaohu.huang9169c492022-11-18 16:30:06 +0800175 if (!(type & LEFT))
176 while (len < size--)
177 *str++ = ' ';
178 for (i = 0; i < len; ++i)
179 *str++ = tmp[i];
180 while (len < size--)
181 *str++ = ' ';
182
183 return str;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800184}
xiaohu.huang1fd6f112022-05-24 11:02:05 +0800185
xiaohu.huang9169c492022-11-18 16:30:06 +0800186char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
187char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
188static void ee_bufcpy(char *d, char *s, int count);
189
190void ee_bufcpy(char *pd, char *ps, int count)
191{
192 char *pe = ps + count;
193
194 while (ps != pe)
195 *pd++ = *ps++;
196}
197
198static void parse_float(double value, char *buffer, char fmt, int precision)
199{
200 int decpt, sign, exp, pos;
201 char *digits = NULL;
202 char cvtbuf[80];
203 int capexp = 0;
204 int magnitude;
205
206 if (fmt == 'G' || fmt == 'E') {
207 capexp = 1;
208 fmt += 'a' - 'A';
209 }
210
211 if (fmt == 'g') {
212 digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
213 magnitude = decpt - 1;
214 if (magnitude < -4 || magnitude > precision - 1) {
215 fmt = 'e';
216 precision -= 1;
217 } else {
218 fmt = 'f';
219 precision -= decpt;
220 }
221 }
222
223 if (fmt == 'e') {
224 digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
225
226 if (sign)
227 *buffer++ = '-';
228 *buffer++ = *digits;
229 if (precision > 0)
230 *buffer++ = '.';
231 ee_bufcpy(buffer, digits + 1, precision);
232 buffer += precision;
233 *buffer++ = capexp ? 'E' : 'e';
234
235 if (decpt == 0) {
236 if (value == 0.0)
237 exp = 0;
238 else
239 exp = -1;
240 } else
241 exp = decpt - 1;
242
243 if (exp < 0) {
244 *buffer++ = '-';
245 exp = -exp;
246 } else
247 *buffer++ = '+';
248
249 buffer[2] = (exp % 10) + '0';
250 exp = exp / 10;
251 buffer[1] = (exp % 10) + '0';
252 exp = exp / 10;
253 buffer[0] = (exp % 10) + '0';
254 buffer += 3;
255 } else if (fmt == 'f') {
256 digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
257 if (sign)
258 *buffer++ = '-';
259 if (*digits) {
260 if (decpt <= 0) {
261 *buffer++ = '0';
262 *buffer++ = '.';
263 for (pos = 0; pos < -decpt; pos++)
264 *buffer++ = '0';
265 while (*digits)
266 *buffer++ = *digits++;
267 } else {
268 pos = 0;
269 while (*digits) {
270 if (pos++ == decpt)
271 *buffer++ = '.';
272 *buffer++ = *digits++;
273 }
274 }
275 } else {
276 *buffer++ = '0';
277 if (precision > 0) {
278 *buffer++ = '.';
279 for (pos = 0; pos < precision; pos++)
280 *buffer++ = '0';
281 }
282 }
283 }
284
285 *buffer = '\0';
286}
287
288static void decimal_point(char *buffer)
289{
290 while (*buffer) {
291 if (*buffer == '.')
292 return;
293 if (*buffer == 'e' || *buffer == 'E')
294 break;
295 buffer++;
296 }
297
298 if (*buffer) {
299 int n = strnlen(buffer, 256);
300
301 while (n > 0) {
302 buffer[n + 1] = buffer[n];
303 n--;
304 }
305
306 *buffer = '.';
307 } else {
308 *buffer++ = '.';
309 *buffer = '\0';
310 }
311}
312
313static void cropzeros(char *buffer)
314{
315 char *stop;
316
317 while (*buffer && *buffer != '.')
318 buffer++;
319 if (*buffer++) {
320 while (*buffer && *buffer != 'e' && *buffer != 'E')
321 buffer++;
322 stop = buffer--;
323 while (*buffer == '0')
324 buffer--;
325 if (*buffer == '.')
326 buffer--;
327 while (buffer != stop)
328 *++buffer = 0;
329 }
330}
331
332static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
333{
334 char tmp[80];
335 char c, sign;
336 int n, i;
337
338 // Left align means no zero padding
339 if (flags & LEFT)
340 flags &= ~ZEROPAD;
341
342 // Determine padding and sign char
343 c = (flags & ZEROPAD) ? '0' : ' ';
344 sign = 0;
345 if (flags & SIGN) {
346 if (num < 0.0) {
347 sign = '-';
348 num = -num;
349 size--;
350 } else if (flags & PLUS) {
351 sign = '+';
352 size--;
353 } else if (flags & SPACE) {
354 sign = ' ';
355 size--;
356 }
357 }
358
359 // Compute the precision value
360 if (precision < 0)
361 precision = 6; // Default precision: 6
362
363 // Convert floating point number to text
364 parse_float(num, tmp, fmt, precision);
365
366 if ((flags & HEX_PREP) && precision == 0)
367 decimal_point(tmp);
368 if (fmt == 'g' && !(flags & HEX_PREP))
369 cropzeros(tmp);
370
371 n = strnlen(tmp, 256);
372
373 // Output number with alignment and padding
374 size -= n;
375 if (!(flags & (ZEROPAD | LEFT)))
376 while (size-- > 0)
377 *str++ = ' ';
378 if (sign)
379 *str++ = sign;
380 if (!(flags & LEFT))
381 while (size-- > 0)
382 *str++ = c;
383 for (i = 0; i < n; i++)
384 *str++ = tmp[i];
385 while (size-- > 0)
386 *str++ = ' ';
387
388 return str;
389}
390
391int aml_vsprintf(char *buf, const char *fmt, va_list args)
392{
393 int len;
394 unsigned long num;
395 int i, base;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800396 char *str;
xiaohu.huang9169c492022-11-18 16:30:06 +0800397 char *s;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800398
xiaohu.huang9169c492022-11-18 16:30:06 +0800399 int flags; // Flags to number()
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800400
xiaohu.huang9169c492022-11-18 16:30:06 +0800401 int field_width; // Width of output field
402 int precision; // Min. # of digits for integers; max number of chars for from string
403 int qualifier; // 'h', 'l', or 'L' for integer fields
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800404
xiaohu.huang9169c492022-11-18 16:30:06 +0800405 for (str = buf; *fmt; fmt++) {
406 if (*fmt != '%') {
407 *str++ = *fmt;
408 continue;
409 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800410
xiaohu.huang9169c492022-11-18 16:30:06 +0800411 // Process flags
412 flags = 0;
413repeat:
414 fmt++; // This also skips first '%'
415 switch (*fmt) {
416 case '-':
417 flags |= LEFT;
418 goto repeat;
419 case '+':
420 flags |= PLUS;
421 goto repeat;
422 case ' ':
423 flags |= SPACE;
424 goto repeat;
425 case '#':
426 flags |= HEX_PREP;
427 goto repeat;
428 case '0':
429 flags |= ZEROPAD;
430 goto repeat;
431 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800432
xiaohu.huang9169c492022-11-18 16:30:06 +0800433 // Get field width
434 field_width = -1;
435 if (isdigit(*fmt))
436 field_width = skip_atoi(&fmt);
437 else if (*fmt == '*') {
438 fmt++;
439 field_width = va_arg(args, int);
440 if (field_width < 0) {
441 field_width = -field_width;
442 flags |= LEFT;
443 }
444 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800445
xiaohu.huang9169c492022-11-18 16:30:06 +0800446 // Get the precision
447 precision = -1;
448 if (*fmt == '.') {
449 ++fmt;
450 if (isdigit(*fmt))
451 precision = skip_atoi(&fmt);
452 else if (*fmt == '*') {
453 ++fmt;
454 precision = va_arg(args, int);
455 }
456 if (precision < 0)
457 precision = 0;
458 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800459
xiaohu.huang9169c492022-11-18 16:30:06 +0800460 // Get the conversion qualifier
461 qualifier = -1;
462 if (*fmt == 'l' || *fmt == 'L') {
463 qualifier = *fmt;
464 fmt++;
465 }
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800466
xiaohu.huang9169c492022-11-18 16:30:06 +0800467 // Default base
468 base = 10;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800469
xiaohu.huang9169c492022-11-18 16:30:06 +0800470 switch (*fmt) {
471 case 'c':
472 if (!(flags & LEFT))
473 while (--field_width > 0)
474 *str++ = ' ';
475 *str++ = (unsigned char)va_arg(args, int);
476 while (--field_width > 0)
477 *str++ = ' ';
478 continue;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800479
xiaohu.huang9169c492022-11-18 16:30:06 +0800480 case 's':
481 s = va_arg(args, char *);
482 if (!s)
483 s = "<NULL>";
484 len = strnlen(s, MAX_BUFFER_LEN - (str-buf) - 1);
485 if (!(flags & LEFT))
486 while (len < field_width--)
487 *str++ = ' ';
488 for (i = 0; i < len; ++i)
489 *str++ = *s++;
490 while (len < field_width--)
491 *str++ = ' ';
492 continue;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800493
xiaohu.huang9169c492022-11-18 16:30:06 +0800494 case 'p':
495 if (field_width == -1) {
496 field_width = 2 * sizeof(void *);
497 flags |= ZEROPAD;
498 }
499 str = number(str, (unsigned long)va_arg(args, void *), 16, field_width,
500 precision, flags);
501 continue;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800502
xiaohu.huang9169c492022-11-18 16:30:06 +0800503 case 'A':
504 flags |= UPPERCASE;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800505
xiaohu.huang9169c492022-11-18 16:30:06 +0800506 case 'a':
507 if (qualifier == 'l')
508 str = eaddr(str, va_arg(args, unsigned char *), field_width,
509 precision, flags);
510 else
511 str = iaddr(str, va_arg(args, unsigned char *), field_width,
512 precision, flags);
513 continue;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800514
xiaohu.huang9169c492022-11-18 16:30:06 +0800515 // Integer number formats - set up the flags and "break"
516 case 'o':
517 base = 8;
518 break;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800519
xiaohu.huang9169c492022-11-18 16:30:06 +0800520 case 'X':
521 flags |= UPPERCASE;
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800522
xiaohu.huang9169c492022-11-18 16:30:06 +0800523 case 'x':
524 base = 16;
525 break;
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800526
xiaohu.huang9169c492022-11-18 16:30:06 +0800527 case 'd':
528 case 'i':
529 flags |= SIGN;
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800530
xiaohu.huang9169c492022-11-18 16:30:06 +0800531 case 'u':
532 break;
533
534#if HAS_FLOAT
535 case 'f':
536 str = flt(str, va_arg(args, double), field_width, precision, *fmt,
537 flags | SIGN);
538 continue;
539
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800540#endif
xiaohu.huang9169c492022-11-18 16:30:06 +0800541
542 default:
543 if (*fmt != '%')
544 *str++ = '%';
545 if (*fmt)
546 *str++ = *fmt;
547 else
548 --fmt;
549 continue;
550 }
551
552 if (qualifier == 'l')
553 num = va_arg(args, unsigned long);
554 else if (flags & SIGN)
555 num = va_arg(args, int);
556 else
557 num = va_arg(args, unsigned int);
558
559 str = number(str, num, base, field_width, precision, flags);
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800560 }
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800561
xiaohu.huang9169c492022-11-18 16:30:06 +0800562 *str = '\0';
563 return str - buf;
bin.chenf2a61ab2022-01-07 17:29:02 +0800564}
565
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800566int printf(const char *fmt, ...)
567{
568 va_list args;
xiaohu.huang9169c492022-11-18 16:30:06 +0800569 char *p = printbuffer;
570 int n = 0;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800571
572 va_start(args, fmt);
xiaohu.huang9169c492022-11-18 16:30:06 +0800573 aml_vsprintf(printbuffer, fmt, args);
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800574 va_end(args);
xiaohu.huang9169c492022-11-18 16:30:06 +0800575
576 while (*p) {
577 if ('\n' == *p) {
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800578#if (1 == CONFIG_ARM64)
xiaohu.huang9169c492022-11-18 16:30:06 +0800579 vSerialPutChar(ConsoleSerial, '\r');
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800580#else
xiaohu.huang9169c492022-11-18 16:30:06 +0800581 vUartPutc('\r');
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800582#endif
xiaohu.huang9169c492022-11-18 16:30:06 +0800583 n++;
584 }
585#if (1 == CONFIG_ARM64)
586 vSerialPutChar(ConsoleSerial, *p);
587#else
588 vUartPutc(*p);
589#endif
590 n++;
591 p++;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800592 }
xiaohu.huang9169c492022-11-18 16:30:06 +0800593
594 return n;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800595}
596
xiaohu.huang9169c492022-11-18 16:30:06 +0800597int iprintf(const char *fmt, ...)
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800598{
xiaohu.huang9169c492022-11-18 16:30:06 +0800599 va_list args;
600 int n = 0;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800601
xiaohu.huang9169c492022-11-18 16:30:06 +0800602 va_start(args, fmt);
603 n = printf(fmt, args);
604 va_end(args);
605
606 return n;
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800607}
608
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800609int puts(const char *str)
610{
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800611#if (1 == CONFIG_ARM64)
xiaohu.huang9169c492022-11-18 16:30:06 +0800612 return vSerialPutString(ConsoleSerial, str);
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800613#else
xiaohu.huang9169c492022-11-18 16:30:06 +0800614 return vUartPuts(str);
Xiaohu.Huang448314d2021-12-31 17:12:48 +0800615#endif
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800616}