blob: 2eb233256e8355ff42187b135920ef8c24cd252b [file] [log] [blame]
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +08001/*
2 * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
3 *
4 * All information contained herein is Amlogic confidential.
5 *
6 * This software is provided to you pursuant to Software License Agreement
7 * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
8 * only in accordance with the terms of this agreement.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification is strictly prohibited without prior written permission from
12 * Amlogic.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/* Printf-like functionality for Chrome EC */
28
29#include "aml_printf.h"
30#include "projdefs.h"
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080031//#include <stdarg.h>
32//#include <stdlib.h>
33//#include <stdio.h>
34#include <string.h>
35#include "uart.h"
36#include "FreeRTOS.h"
37#include "task.h" /* RTOS task related API prototypes. */
38
39static const char error_str[] = "ERROR";
40
41#define MAX_FORMAT 1024 /* Maximum chars in a single format field */
42static char printbuffer[512];
43
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080044#ifndef MAX
45#define MAX(a, b) \
46 ({ \
47 __typeof__(a) temp_a = (a); \
48 __typeof__(b) temp_b = (b); \
49 \
50 temp_a > temp_b ? temp_a : temp_b; \
51 })
52#endif
53
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +080054/**
55 * Convert the lowest nibble of a number to hex
56 *
57 * @param c Number to extract lowest nibble from
58 *
59 * @return The corresponding ASCII character ('0' - 'f').
60 */
61static int hexdigit(int c)
62{
63 /* Strip off just the last nibble */
64 c &= 0x0f;
65
66 return c > 9 ? (c + 'a' - 10) : (c + '0');
67}
68
Xiaohu.Huangaa18c4c2021-11-16 17:26:41 +080069static int uint64divmod(uint64_t *n, int d)
70{
71 uint64_t q = 0, mask;
72 int r = 0;
73
74 /* Divide-by-zero returns zero */
75 if (!d) {
76 *n = 0;
77 return 0;
78 }
79
80 /* Common powers of 2 = simple shifts */
81 if (d == 2) {
82 r = *n & 1;
83 *n >>= 1;
84 return r;
85 } else if (d == 16) {
86 r = *n & 0xf;
87 *n >>= 4;
88 return r;
89 }
90
91 /* If v fits in 32-bit, we're done. */
92 if (*n <= 0xffffffff) {
93 uint32_t v32 = *n;
94 r = v32 % d;
95 *n = v32 / d;
96 return r;
97 }
98
99 /* Otherwise do integer division the slow way. */
100 for (mask = (1ULL << 63); mask; mask >>= 1) {
101 r <<= 1;
102 if (*n & mask)
103 r |= 1;
104 if (r >= d) {
105 r -= d;
106 q |= mask;
107 }
108 }
109 *n = q;
110 return r;
111}
112
Xiaohu.Huang60a7f2f2021-10-25 15:40:57 +0800113/* Flags for vfnprintf() flags */
114#define PF_LEFT (1 << 0) /* Left-justify */
115#define PF_PADZERO (1 << 1) /* Pad with 0's not spaces */
116#define PF_NEGATIVE (1 << 2) /* Number is negative */
117#define PF_64BIT (1 << 3) /* Number is 64-bit */
118#if 1
119int vfnprintf(int (*addchar)(void *context, int c), void *context,
120 const char *format, va_list args)
121{
122 /*
123 * Longest uint64 in decimal = 20
124 * Longest uint32 in binary = 32
125 * + sign bit
126 * + terminating null
127 */
128 char intbuf[34];
129 int flags;
130 int pad_width;
131 int precision;
132 char *vstr;
133 int vlen;
134
135 while (*format) {
136 int c = *format++;
137
138 /* Copy normal characters */
139 if (c != '%') {
140 if (addchar(context, c))
141 return pdFREERTOS_ERRNO_EINVAL;
142 continue;
143 }
144
145 /* Zero flags, now that we're in a format */
146 flags = 0;
147
148 /* Get first format character */
149 c = *format++;
150
151 /* Send "%" for "%%" input */
152 if (c == '%' || c == '\0') {
153 if (addchar(context, '%'))
154 return pdFREERTOS_ERRNO_EINVAL;
155 continue;
156 }
157
158 /* Handle %c */
159 if (c == 'c') {
160 c = va_arg(args, int);
161
162 if (addchar(context, c))
163 return pdFREERTOS_ERRNO_EINVAL;
164 continue;
165 }
166
167 /* Handle left-justification ("%-5s") */
168 if (c == '-') {
169 flags |= PF_LEFT;
170 c = *format++;
171 }
172
173 /* Handle padding with 0's */
174 if (c == '0') {
175 flags |= PF_PADZERO;
176 c = *format++;
177 }
178
179 /* Count padding length */
180 pad_width = 0;
181 if (c == '*') {
182 pad_width = va_arg(args, int);
183
184 c = *format++;
185 } else {
186 while (c >= '0' && c <= '9') {
187 pad_width = (10 * pad_width) + c - '0';
188 c = *format++;
189 }
190 }
191 if (pad_width < 0 || pad_width > MAX_FORMAT) {
192 /* Sanity check for precision failed */
193 format = error_str;
194 continue;
195 }
196 /* Count precision */
197 precision = 0;
198 if (c == '.') {
199 c = *format++;
200 if (c == '*') {
201 precision = va_arg(args, int);
202
203 c = *format++;
204 } else {
205 while (c >= '0' && c <= '9') {
206 precision = (10 * precision) + c - '0';
207 c = *format++;
208 }
209 }
210 if (precision < 0 || precision > MAX_FORMAT) {
211 /* Sanity check for precision failed */
212 format = error_str;
213 continue;
214 }
215 }
216
217 if (c == 's') {
218 vstr = va_arg(args, char *);
219
220 if (vstr == NULL) { /*Fix me */
221 ; //vstr = "(NULL)";
222 }
223 } else if (c == 'h') {
224 /* Hex dump output */
225 vstr = va_arg(args, char *);
226
227 if (!precision) {
228 /* Hex dump requires precision */
229 format = error_str;
230 continue;
231 }
232
233 for (; precision; precision--, vstr++) {
234 if (addchar(context, hexdigit(*vstr >> 4)) ||
235 addchar(context, hexdigit(*vstr)))
236 return pdFREERTOS_ERRNO_EINVAL;
237 }
238
239 continue;
240 } else {
241 uint64_t v;
242 int base = 10;
243
244 /* Handle length */
245 if (c == 'l') {
246 if (sizeof(long) == 8)
247 flags |= PF_64BIT;
248 c = *format++;
249 if (c == 'l') {
250 flags |= PF_64BIT;
251 c = *format++; // long long is 64bit at LP64
252 }
253 }
254
255 /* Special-case: %T = current time */
256 if (c == 'T') {
257 //v = get_time().val;
258 flags |= PF_64BIT;
259 precision = 6;
260 } else if (flags & PF_64BIT) {
261 v = va_arg(args, uint64_t);
262 } else {
263 v = va_arg(args, uint32_t);
264 }
265
266 switch (c) {
267 case 'd':
268 if (flags & PF_64BIT) {
269 if ((int64_t) v < 0) {
270 flags |= PF_NEGATIVE;
271 if (v != (1ULL << 63))
272 v = -v;
273 }
274 } else {
275 if ((int)v < 0) {
276 flags |= PF_NEGATIVE;
277 if (v != (1ULL << 31))
278 v = -(int)v;
279 }
280 }
281 break;
282 case 'u':
283 case 'T':
284 break;
285 case 'X':
286 case 'x':
287 case 'p':
288 base = 16;
289 break;
290 case 'b':
291 base = 2;
292 break;
293 default:
294 format = error_str;
295 }
296 if (format == error_str)
297 continue; /* Bad format specifier */
298
299 /*
300 * Convert integer to string, starting at end of
301 * buffer and working backwards.
302 */
303 vstr = intbuf + sizeof(intbuf) - 1;
304 *(vstr) = '\0';
305
306 /*
307 * Fixed-point precision must fit in our buffer.
308 * Leave space for "0." and the terminating null.
309 */
310 if (precision > (int)(sizeof(intbuf) - 3))
311 precision = (int)(sizeof(intbuf) - 3);
312
313 /*
314 * Handle digits to right of decimal for fixed point
315 * numbers.
316 */
317 for (vlen = 0; vlen < precision; vlen++)
318 *(--vstr) = '0' + uint64divmod(&v, 10);
319 if (precision)
320 *(--vstr) = '.';
321
322 if (!v)
323 *(--vstr) = '0';
324
325 while (v) {
326 int digit = uint64divmod(&v, base);
327
328 if (digit < 10)
329 *(--vstr) = '0' + digit;
330 else if (c == 'X')
331 *(--vstr) = 'A' + digit - 10;
332 else
333 *(--vstr) = 'a' + digit - 10;
334 }
335
336 if (flags & PF_NEGATIVE)
337 *(--vstr) = '-';
338
339 /*
340 * Precision field was interpreted by fixed-point
341 * logic, so clear it.
342 */
343 precision = 0;
344 }
345
346 /* Copy string (or stringified integer) */
347 if (vstr != NULL)
348 vlen = strlen(vstr);
349 else
350 vlen = 0;
351
352 /* No padding strings to wider than the precision */
353 if (precision > 0 && pad_width > precision)
354 pad_width = precision;
355
356 /* If precision is zero, print everything */
357 if (!precision)
358 precision = MAX(vlen, pad_width);
359
360 while (vlen < pad_width && !(flags & PF_LEFT)) {
361 if (addchar(context, flags & PF_PADZERO ? '0' : ' '))
362 return pdFREERTOS_ERRNO_EINVAL;
363 vlen++;
364 }
365
366 if (vstr != NULL) {
367 while (*vstr && --precision >= 0)
368 if (addchar(context, *vstr++))
369 return pdFREERTOS_ERRNO_EINVAL;
370 }
371 while (vlen < pad_width && flags & PF_LEFT) {
372 if (addchar(context, ' '))
373 return pdFREERTOS_ERRNO_EINVAL;
374 vlen++;
375 }
376 }
377
378 /* If we're still here, we consumed all output */
379 return pdFREERTOS_ERRNO_NONE;
380}
381#endif
382/* Context for snprintf() */
383struct snprintf_context {
384 char *str;
385 size_t size;
386};
387
388/**
389 * Add a character to the string context.
390 *
391 * @param context Context receiving character
392 * @param c Character to add
393 * @return 0 if character added, 1 if character dropped because no space.
394 */
395static int snprintf_addchar(void *context, int c)
396{
397 struct snprintf_context *ctx = (struct snprintf_context *)context;
398
399 if (!ctx->size)
400 return 1;
401
402 *(ctx->str++) = c;
403 ctx->size--;
404
405 return 0;
406}
407
408int sPrintf_ext(char *str, size_t size, const char *format, va_list args)
409{
410 struct snprintf_context ctx;
411 int rv;
412
413 if (!str || !size)
414 return pdFREERTOS_ERRNO_EINVAL;
415
416 ctx.str = str;
417 ctx.size = size - 1; /* Reserve space for terminating '\0' */
418
419 rv = vfnprintf(snprintf_addchar, &ctx, format, args);
420
421 /* Terminate string */
422 *ctx.str = '\0';
423
424 return rv;
425}
426
427int sPrintf(char *str, size_t size, const char *fmt, ...)
428{
429 va_list args;
430 int i;
431
432 va_start(args, fmt);
433
434 i = sPrintf_ext(str, size, fmt, args);
435 va_end(args);
436
437 return i;
438}
439
440//int iprintf(const char *fmt, ...)
441int printf(const char *fmt, ...)
442{
443 va_list args;
444 int i;
445 UBaseType_t uxSavedInterruptStatus;
446
447 //char buf[20] = {0};
448
449 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
450
451 va_start(args, fmt);
452
453 /* For this to work, printbuffer must be larger than
454 * anything we ever want to print.
455 */
456 i = sPrintf_ext(printbuffer, sizeof(printbuffer), fmt, args);
457 va_end(args);
458 {
459 /* Print the string */
460 //sprintf(buf, "%lld : ", (long long int)xTaskGetTickCount());
461 //vSerialPutString(ConsoleSerial, buf);
462 //vSerialPutString(ConsoleSerial, printbuffer);
463 vUartPuts(printbuffer);
464 }
465 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
466 return i;
467}
468
469int iprint_string(char *str)
470{
471 //vSerialPutString(ConsoleSerial, str);
472 vUartPuts(str);
473
474 return 0;
475}
476
477extern int puts(const char *str);
478
479int puts(const char *str)
480{
481 vUartPuts(str);
482
483 return 0;
484}
485