blob: b0625575f262eafa690e8b5ab0988f6ed8ba26a7 [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"
31#include "util.h"
32//#include <stdarg.h>
33//#include <stdlib.h>
34//#include <stdio.h>
35#include <string.h>
36#include "uart.h"
37#include "FreeRTOS.h"
38#include "task.h" /* RTOS task related API prototypes. */
39
40static const char error_str[] = "ERROR";
41
42#define MAX_FORMAT 1024 /* Maximum chars in a single format field */
43static char printbuffer[512];
44
45/**
46 * Convert the lowest nibble of a number to hex
47 *
48 * @param c Number to extract lowest nibble from
49 *
50 * @return The corresponding ASCII character ('0' - 'f').
51 */
52static int hexdigit(int c)
53{
54 /* Strip off just the last nibble */
55 c &= 0x0f;
56
57 return c > 9 ? (c + 'a' - 10) : (c + '0');
58}
59
60/* Flags for vfnprintf() flags */
61#define PF_LEFT (1 << 0) /* Left-justify */
62#define PF_PADZERO (1 << 1) /* Pad with 0's not spaces */
63#define PF_NEGATIVE (1 << 2) /* Number is negative */
64#define PF_64BIT (1 << 3) /* Number is 64-bit */
65#if 1
66int vfnprintf(int (*addchar)(void *context, int c), void *context,
67 const char *format, va_list args)
68{
69 /*
70 * Longest uint64 in decimal = 20
71 * Longest uint32 in binary = 32
72 * + sign bit
73 * + terminating null
74 */
75 char intbuf[34];
76 int flags;
77 int pad_width;
78 int precision;
79 char *vstr;
80 int vlen;
81
82 while (*format) {
83 int c = *format++;
84
85 /* Copy normal characters */
86 if (c != '%') {
87 if (addchar(context, c))
88 return pdFREERTOS_ERRNO_EINVAL;
89 continue;
90 }
91
92 /* Zero flags, now that we're in a format */
93 flags = 0;
94
95 /* Get first format character */
96 c = *format++;
97
98 /* Send "%" for "%%" input */
99 if (c == '%' || c == '\0') {
100 if (addchar(context, '%'))
101 return pdFREERTOS_ERRNO_EINVAL;
102 continue;
103 }
104
105 /* Handle %c */
106 if (c == 'c') {
107 c = va_arg(args, int);
108
109 if (addchar(context, c))
110 return pdFREERTOS_ERRNO_EINVAL;
111 continue;
112 }
113
114 /* Handle left-justification ("%-5s") */
115 if (c == '-') {
116 flags |= PF_LEFT;
117 c = *format++;
118 }
119
120 /* Handle padding with 0's */
121 if (c == '0') {
122 flags |= PF_PADZERO;
123 c = *format++;
124 }
125
126 /* Count padding length */
127 pad_width = 0;
128 if (c == '*') {
129 pad_width = va_arg(args, int);
130
131 c = *format++;
132 } else {
133 while (c >= '0' && c <= '9') {
134 pad_width = (10 * pad_width) + c - '0';
135 c = *format++;
136 }
137 }
138 if (pad_width < 0 || pad_width > MAX_FORMAT) {
139 /* Sanity check for precision failed */
140 format = error_str;
141 continue;
142 }
143 /* Count precision */
144 precision = 0;
145 if (c == '.') {
146 c = *format++;
147 if (c == '*') {
148 precision = va_arg(args, int);
149
150 c = *format++;
151 } else {
152 while (c >= '0' && c <= '9') {
153 precision = (10 * precision) + c - '0';
154 c = *format++;
155 }
156 }
157 if (precision < 0 || precision > MAX_FORMAT) {
158 /* Sanity check for precision failed */
159 format = error_str;
160 continue;
161 }
162 }
163
164 if (c == 's') {
165 vstr = va_arg(args, char *);
166
167 if (vstr == NULL) { /*Fix me */
168 ; //vstr = "(NULL)";
169 }
170 } else if (c == 'h') {
171 /* Hex dump output */
172 vstr = va_arg(args, char *);
173
174 if (!precision) {
175 /* Hex dump requires precision */
176 format = error_str;
177 continue;
178 }
179
180 for (; precision; precision--, vstr++) {
181 if (addchar(context, hexdigit(*vstr >> 4)) ||
182 addchar(context, hexdigit(*vstr)))
183 return pdFREERTOS_ERRNO_EINVAL;
184 }
185
186 continue;
187 } else {
188 uint64_t v;
189 int base = 10;
190
191 /* Handle length */
192 if (c == 'l') {
193 if (sizeof(long) == 8)
194 flags |= PF_64BIT;
195 c = *format++;
196 if (c == 'l') {
197 flags |= PF_64BIT;
198 c = *format++; // long long is 64bit at LP64
199 }
200 }
201
202 /* Special-case: %T = current time */
203 if (c == 'T') {
204 //v = get_time().val;
205 flags |= PF_64BIT;
206 precision = 6;
207 } else if (flags & PF_64BIT) {
208 v = va_arg(args, uint64_t);
209 } else {
210 v = va_arg(args, uint32_t);
211 }
212
213 switch (c) {
214 case 'd':
215 if (flags & PF_64BIT) {
216 if ((int64_t) v < 0) {
217 flags |= PF_NEGATIVE;
218 if (v != (1ULL << 63))
219 v = -v;
220 }
221 } else {
222 if ((int)v < 0) {
223 flags |= PF_NEGATIVE;
224 if (v != (1ULL << 31))
225 v = -(int)v;
226 }
227 }
228 break;
229 case 'u':
230 case 'T':
231 break;
232 case 'X':
233 case 'x':
234 case 'p':
235 base = 16;
236 break;
237 case 'b':
238 base = 2;
239 break;
240 default:
241 format = error_str;
242 }
243 if (format == error_str)
244 continue; /* Bad format specifier */
245
246 /*
247 * Convert integer to string, starting at end of
248 * buffer and working backwards.
249 */
250 vstr = intbuf + sizeof(intbuf) - 1;
251 *(vstr) = '\0';
252
253 /*
254 * Fixed-point precision must fit in our buffer.
255 * Leave space for "0." and the terminating null.
256 */
257 if (precision > (int)(sizeof(intbuf) - 3))
258 precision = (int)(sizeof(intbuf) - 3);
259
260 /*
261 * Handle digits to right of decimal for fixed point
262 * numbers.
263 */
264 for (vlen = 0; vlen < precision; vlen++)
265 *(--vstr) = '0' + uint64divmod(&v, 10);
266 if (precision)
267 *(--vstr) = '.';
268
269 if (!v)
270 *(--vstr) = '0';
271
272 while (v) {
273 int digit = uint64divmod(&v, base);
274
275 if (digit < 10)
276 *(--vstr) = '0' + digit;
277 else if (c == 'X')
278 *(--vstr) = 'A' + digit - 10;
279 else
280 *(--vstr) = 'a' + digit - 10;
281 }
282
283 if (flags & PF_NEGATIVE)
284 *(--vstr) = '-';
285
286 /*
287 * Precision field was interpreted by fixed-point
288 * logic, so clear it.
289 */
290 precision = 0;
291 }
292
293 /* Copy string (or stringified integer) */
294 if (vstr != NULL)
295 vlen = strlen(vstr);
296 else
297 vlen = 0;
298
299 /* No padding strings to wider than the precision */
300 if (precision > 0 && pad_width > precision)
301 pad_width = precision;
302
303 /* If precision is zero, print everything */
304 if (!precision)
305 precision = MAX(vlen, pad_width);
306
307 while (vlen < pad_width && !(flags & PF_LEFT)) {
308 if (addchar(context, flags & PF_PADZERO ? '0' : ' '))
309 return pdFREERTOS_ERRNO_EINVAL;
310 vlen++;
311 }
312
313 if (vstr != NULL) {
314 while (*vstr && --precision >= 0)
315 if (addchar(context, *vstr++))
316 return pdFREERTOS_ERRNO_EINVAL;
317 }
318 while (vlen < pad_width && flags & PF_LEFT) {
319 if (addchar(context, ' '))
320 return pdFREERTOS_ERRNO_EINVAL;
321 vlen++;
322 }
323 }
324
325 /* If we're still here, we consumed all output */
326 return pdFREERTOS_ERRNO_NONE;
327}
328#endif
329/* Context for snprintf() */
330struct snprintf_context {
331 char *str;
332 size_t size;
333};
334
335/**
336 * Add a character to the string context.
337 *
338 * @param context Context receiving character
339 * @param c Character to add
340 * @return 0 if character added, 1 if character dropped because no space.
341 */
342static int snprintf_addchar(void *context, int c)
343{
344 struct snprintf_context *ctx = (struct snprintf_context *)context;
345
346 if (!ctx->size)
347 return 1;
348
349 *(ctx->str++) = c;
350 ctx->size--;
351
352 return 0;
353}
354
355int sPrintf_ext(char *str, size_t size, const char *format, va_list args)
356{
357 struct snprintf_context ctx;
358 int rv;
359
360 if (!str || !size)
361 return pdFREERTOS_ERRNO_EINVAL;
362
363 ctx.str = str;
364 ctx.size = size - 1; /* Reserve space for terminating '\0' */
365
366 rv = vfnprintf(snprintf_addchar, &ctx, format, args);
367
368 /* Terminate string */
369 *ctx.str = '\0';
370
371 return rv;
372}
373
374int sPrintf(char *str, size_t size, const char *fmt, ...)
375{
376 va_list args;
377 int i;
378
379 va_start(args, fmt);
380
381 i = sPrintf_ext(str, size, fmt, args);
382 va_end(args);
383
384 return i;
385}
386
387//int iprintf(const char *fmt, ...)
388int printf(const char *fmt, ...)
389{
390 va_list args;
391 int i;
392 UBaseType_t uxSavedInterruptStatus;
393
394 //char buf[20] = {0};
395
396 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
397
398 va_start(args, fmt);
399
400 /* For this to work, printbuffer must be larger than
401 * anything we ever want to print.
402 */
403 i = sPrintf_ext(printbuffer, sizeof(printbuffer), fmt, args);
404 va_end(args);
405 {
406 /* Print the string */
407 //sprintf(buf, "%lld : ", (long long int)xTaskGetTickCount());
408 //vSerialPutString(ConsoleSerial, buf);
409 //vSerialPutString(ConsoleSerial, printbuffer);
410 vUartPuts(printbuffer);
411 }
412 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
413 return i;
414}
415
416int iprint_string(char *str)
417{
418 //vSerialPutString(ConsoleSerial, str);
419 vUartPuts(str);
420
421 return 0;
422}
423
424extern int puts(const char *str);
425
426int puts(const char *str)
427{
428 vUartPuts(str);
429
430 return 0;
431}
432