1 /*
2  * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdbool.h>
10 #include <stdarg.h>
11 #include <assert.h>
12 #include <unistd.h>
13 #include "esp_rom_sys.h"
14 
15 static void call_linux_putc(char c);
16 
17 static void (*s_esp_rom_putc)(char c) = call_linux_putc;
18 
call_linux_putc(char c)19 static void call_linux_putc(char c) {
20     putc(c, stdout);
21 }
22 
23 #define is_digit(c) ((c >= '0') && (c <= '9'))
24 
_cvt(unsigned long long val,char * buf,long radix,const char * digits)25 static int _cvt(unsigned long long val, char *buf, long radix, const char *digits)
26 {
27 #ifdef SUPPORT_LITTLE_RADIX
28     char temp[64];
29 #else
30     char temp[32];
31 #endif
32     char *cp = temp;
33     int length = 0;
34 
35     if (val == 0) {
36         /* Special case */
37         *cp++ = '0';
38     } else {
39         while (val) {
40             *cp++ = digits[val % radix];
41             val /= radix;
42         }
43     }
44     while (cp != temp) {
45         *buf++ = *--cp;
46         length++;
47     }
48     *buf = '\0';
49     return (length);
50 }
51 
esp_rom_vprintf(void (* putc)(char c),const char * fmt,va_list ap)52 static int esp_rom_vprintf(void (*putc)(char c), const char *fmt, va_list ap)
53 {
54 #ifdef BINARY_SUPPORT
55     char buf[sizeof(long long)*8];
56     int i;
57 #else
58     char buf[32];
59 #endif
60     char c, sign;
61     const char *cp = buf;
62     int left_prec, right_prec, zero_fill, pad, pad_on_right,
63         islong, islonglong;
64     long long val = 0;
65     int res = 0, length = 0;
66 
67     while ((c = *fmt++) != '\0') {
68         if (c == '%') {
69             c = *fmt++;
70             left_prec = right_prec = pad_on_right = islong = islonglong = 0;
71             if (c == '-') {
72                 c = *fmt++;
73                 pad_on_right++;
74             }
75             if (c == '0') {
76                 zero_fill = true;
77                 c = *fmt++;
78             } else {
79                 zero_fill = false;
80             }
81             while (is_digit(c)) {
82                 left_prec = (left_prec * 10) + (c - '0');
83                 c = *fmt++;
84             }
85             if (c == '.') {
86                 c = *fmt++;
87                 zero_fill++;
88                 while (is_digit(c)) {
89                     right_prec = (right_prec * 10) + (c - '0');
90                     c = *fmt++;
91                 }
92             } else {
93                 right_prec = left_prec;
94             }
95             sign = '\0';
96             if (c == 'l') {
97                 c = *fmt++;
98                 islong = 1;
99                 if (c == 'l') {
100                     c = *fmt++;
101                     islonglong = 1;
102                 }
103             }
104             switch (c) {
105             case 'p':
106                 islong = 1;
107             case 'd':
108             case 'D':
109             case 'x':
110             case 'X':
111             case 'u':
112             case 'U':
113 #ifdef BINARY_SUPPORT
114             case 'b':
115             case 'B':
116 #endif
117                 if (islonglong) {
118                     val = va_arg(ap, long long);
119                 } else if (islong) {
120                     val = (long long)va_arg(ap, long);
121                 } else{
122                     val = (long long)va_arg(ap, int);
123                 }
124                 if ((c == 'd') || (c == 'D')) {
125                     if (val < 0) {
126                         sign = '-';
127                         val = -val;
128                     }
129                 } else {
130                     if (islong) {
131                         val &= (((long long)1) << (sizeof(long) * 8)) - 1;
132                     } else{
133                         val &= (((long long)1) << (sizeof(int) * 8)) - 1;
134                     }
135                 }
136                 break;
137             default:
138                 break;
139             }
140 
141             switch (c) {
142             case 'p':
143                 (*putc)('0');
144                 (*putc)('x');
145                 zero_fill = true;
146                 left_prec = sizeof(unsigned long)*2;
147             case 'd':
148             case 'D':
149             case 'u':
150             case 'U':
151             case 'x':
152             case 'X':
153                 switch (c) {
154                 case 'd':
155                 case 'D':
156                 case 'u':
157                 case 'U':
158                     length = _cvt(val, buf, 10, "0123456789");
159                     break;
160                 case 'p':
161                 case 'x':
162                     length = _cvt(val, buf, 16, "0123456789abcdef");
163                     break;
164                 case 'X':
165                     length = _cvt(val, buf, 16, "0123456789ABCDEF");
166                     break;
167                 }
168                 cp = buf;
169                 break;
170             case 's':
171             case 'S':
172                 cp = va_arg(ap, char *);
173                 if (cp == NULL)  {
174                     cp = "<null>";
175                 }
176                 length = 0;
177                 while (cp[length] != '\0') length++;
178                 break;
179             case 'c':
180             case 'C':
181                 c = va_arg(ap, int /*char*/);
182                 (*putc)(c);
183                 res++;
184                 continue;
185 #ifdef BINARY_SUPPORT
186             case 'b':
187             case 'B':
188                 length = left_prec;
189                 if (left_prec == 0) {
190                     if (islonglong)
191                         length = sizeof(long long)*8;
192                     else if (islong)
193                         length = sizeof(long)*8;
194                     else
195                         length = sizeof(int)*8;
196                 }
197                 for (i = 0;  i < length-1;  i++) {
198                     buf[i] = ((val & ((long long)1<<i)) ? '1' : '.');
199                 }
200                 cp = buf;
201                 break;
202 #endif
203             case '%':
204                 (*putc)('%');
205                 break;
206             default:
207                 (*putc)('%');
208                 (*putc)(c);
209                 res += 2;
210             }
211             pad = left_prec - length;
212             if (sign != '\0') {
213                 pad--;
214             }
215             if (zero_fill) {
216                 c = '0';
217                 if (sign != '\0') {
218                     (*putc)(sign);
219                     res++;
220                     sign = '\0';
221                 }
222             } else {
223                 c = ' ';
224             }
225             if (!pad_on_right) {
226                 while (pad-- > 0) {
227                     (*putc)(c);
228                     res++;
229                 }
230             }
231             if (sign != '\0') {
232                 (*putc)(sign);
233                 res++;
234             }
235             while (length-- > 0) {
236                 c = *cp++;
237                 (*putc)(c);
238                 res++;
239             }
240             if (pad_on_right) {
241                 while (pad-- > 0) {
242                     (*putc)(' ');
243                     res++;
244                 }
245             }
246         } else {
247             (*putc)(c);
248             res++;
249         }
250     }
251     return (res);
252 }
253 
esp_rom_printf(const char * fmt,...)254 int esp_rom_printf(const char *fmt, ...)
255 {
256 
257     va_list list;
258     va_start(list, fmt);
259     int result = esp_rom_vprintf(s_esp_rom_putc, fmt, list);
260     va_end(list);
261     return result;
262 }
263 
esp_rom_delay_us(uint32_t us)264 void esp_rom_delay_us(uint32_t us)
265 {
266     int sleep_result = usleep(us);
267     assert(sleep_result == 0);
268     (void)sleep_result; // Prevents compiler from optimizing out usleep() due to unused result. Also prevents warning.
269 }
270 
esp_rom_install_channel_putc(int channel,void (* putc)(char c))271 void esp_rom_install_channel_putc(int channel, void (*putc)(char c))
272 {
273     if (putc != NULL) {
274         s_esp_rom_putc = putc;
275     }
276 }
277 
esp_rom_install_uart_printf(void)278 void esp_rom_install_uart_printf(void)
279 {
280     // Since this is the linux implementation, we don't set any "UART" putc function, but the one which delegates to
281     // the Linux libc version of putc.
282     s_esp_rom_putc = call_linux_putc;
283 }
284 
esp_rom_get_reset_reason(int cpu_no)285 soc_reset_reason_t esp_rom_get_reset_reason(int cpu_no)
286 {
287     return RESET_REASON_CHIP_POWER_ON;
288 }
289