1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8 #include "esp_log.h"
9 #include "esp_app_trace.h"
10 #include "esp_app_trace_port.h"
11
12 #define ESP_APPTRACE_MAX_VPRINTF_ARGS 256
13 #define ESP_APPTRACE_HOST_BUF_SIZE 256
14
15 #define ESP_APPTRACE_PRINT_LOCK 0
16
17 const static char *TAG = "esp_apptrace";
18
19 /** tracing module internal data */
20 typedef struct {
21 esp_apptrace_hw_t * hw;
22 void * hw_data;
23 } esp_apptrace_channel_t;
24
25 static esp_apptrace_channel_t s_trace_channels[ESP_APPTRACE_DEST_NUM];
26 static bool s_inited;
27
esp_apptrace_init(void)28 esp_err_t esp_apptrace_init(void)
29 {
30 int res;
31 esp_apptrace_hw_t *hw = NULL;
32 void *hw_data = NULL;
33
34 // 'esp_apptrace_init()' is called on every core, so ensure to do main initialization only once
35 if (cpu_hal_get_core_id() == 0) {
36 memset(&s_trace_channels, 0, sizeof(s_trace_channels));
37 hw = esp_apptrace_jtag_hw_get(&hw_data);
38 ESP_APPTRACE_LOGD("HW interface %p", hw);
39 if (hw != NULL) {
40 s_trace_channels[ESP_APPTRACE_DEST_JTAG].hw = hw;
41 s_trace_channels[ESP_APPTRACE_DEST_JTAG].hw_data = hw_data;
42 }
43 hw = esp_apptrace_uart_hw_get(0, &hw_data);
44 if (hw != NULL) {
45 s_trace_channels[ESP_APPTRACE_DEST_UART0].hw = hw;
46 s_trace_channels[ESP_APPTRACE_DEST_UART0].hw_data = hw_data;
47 }
48 s_inited = true;
49 }
50
51 // esp_apptrace_init() is called on every core, so initialize trace channel on every core
52 for (int i = 0; i < sizeof(s_trace_channels)/sizeof(s_trace_channels[0]); i++) {
53 esp_apptrace_channel_t *ch = &s_trace_channels[i];
54 if (ch->hw) {
55 res = ch->hw->init(ch->hw_data);
56 if (res != ESP_OK) {
57 ESP_APPTRACE_LOGE("Failed to init trace channel HW interface (%d)!", res);
58 return res;
59 }
60 }
61 }
62
63 return ESP_OK;
64 }
65
esp_apptrace_down_buffer_config(uint8_t * buf,uint32_t size)66 void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size)
67 {
68 esp_apptrace_channel_t *ch;
69
70 if (!s_inited) {
71 return;
72 }
73 // currently down buffer is supported for JTAG interface only
74 // TODO: one more argument should be added to this function to specify HW inteface: JTAG, UART0 etc
75 ch = &s_trace_channels[ESP_APPTRACE_DEST_JTAG];
76 if (ch->hw == NULL) {
77 ESP_APPTRACE_LOGE("Trace destination not supported!");
78 return;
79 }
80 if (ch->hw->down_buffer_config == NULL) {
81 return;
82 }
83
84 ch->hw->down_buffer_config(ch->hw_data, buf, size);
85 }
86
esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest,uint32_t * size,uint32_t user_tmo)87 uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t user_tmo)
88 {
89 esp_apptrace_tmo_t tmo;
90 esp_apptrace_channel_t *ch;
91
92 ESP_APPTRACE_LOGV("%s(): enter", __func__);
93 if (dest >= ESP_APPTRACE_DEST_MAX) {
94 return NULL;
95 }
96 if (size == NULL || *size == 0) {
97 return NULL;
98 }
99 if (!s_inited) {
100 return NULL;
101 }
102 ch = &s_trace_channels[dest];
103 if (ch->hw == NULL) {
104 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
105 return NULL;
106 }
107 if (ch->hw->get_down_buffer == NULL) {
108 return NULL;
109 }
110
111 esp_apptrace_tmo_init(&tmo, user_tmo);
112 return ch->hw->get_down_buffer(ch->hw_data, size, &tmo);
113 }
114
esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest,uint8_t * ptr,uint32_t user_tmo)115 esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo)
116 {
117 esp_apptrace_tmo_t tmo;
118 esp_apptrace_channel_t *ch;
119
120 ESP_APPTRACE_LOGV("%s(): enter", __func__);
121 if (dest >= ESP_APPTRACE_DEST_MAX) {
122 return ESP_ERR_INVALID_ARG;
123 }
124 if (ptr == NULL) {
125 return ESP_ERR_INVALID_ARG;
126 }
127 if (!s_inited) {
128 return ESP_ERR_INVALID_STATE;
129 }
130 ch = &s_trace_channels[dest];
131 if (ch->hw == NULL) {
132 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
133 return ESP_ERR_NOT_SUPPORTED;
134 }
135 if (ch->hw->get_down_buffer == NULL) {
136 return ESP_ERR_NOT_SUPPORTED;
137 }
138
139 esp_apptrace_tmo_init(&tmo, user_tmo);
140 return ch->hw->put_down_buffer(ch->hw_data, ptr, &tmo);
141 }
142
esp_apptrace_read(esp_apptrace_dest_t dest,void * buf,uint32_t * size,uint32_t user_tmo)143 esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, uint32_t *size, uint32_t user_tmo)
144 {
145 int res = ESP_OK;
146 esp_apptrace_tmo_t tmo;
147 esp_apptrace_channel_t *ch;
148
149 ESP_APPTRACE_LOGV("%s(): enter", __func__);
150 if (dest >= ESP_APPTRACE_DEST_MAX) {
151 return ESP_ERR_INVALID_ARG;
152 }
153 if (buf == NULL || size == NULL || *size == 0) {
154 return ESP_ERR_INVALID_ARG;
155 }
156 if (!s_inited) {
157 return ESP_ERR_INVALID_STATE;
158 }
159 ch = &s_trace_channels[dest];
160 if (ch->hw == NULL) {
161 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
162 return ESP_ERR_NOT_SUPPORTED;
163 }
164 if (ch->hw->get_down_buffer == NULL || ch->hw->put_down_buffer == NULL) {
165 return ESP_ERR_NOT_SUPPORTED;
166 }
167
168 //TODO: callback system
169 esp_apptrace_tmo_init(&tmo, user_tmo);
170 uint32_t act_sz = *size;
171 *size = 0;
172 uint8_t * ptr = ch->hw->get_down_buffer(ch->hw_data, &act_sz, &tmo);
173 if (ptr && act_sz > 0) {
174 ESP_APPTRACE_LOGD("Read %d bytes from host", act_sz);
175 memcpy(buf, ptr, act_sz);
176 res = ch->hw->put_down_buffer(ch->hw_data, ptr, &tmo);
177 *size = act_sz;
178 } else {
179 res = ESP_ERR_TIMEOUT;
180 }
181
182 return res;
183 }
184
esp_apptrace_buffer_get(esp_apptrace_dest_t dest,uint32_t size,uint32_t user_tmo)185 uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t user_tmo)
186 {
187 esp_apptrace_tmo_t tmo;
188 esp_apptrace_channel_t *ch;
189
190 ESP_APPTRACE_LOGV("%s(): enter", __func__);
191 if (dest >= ESP_APPTRACE_DEST_MAX) {
192 return NULL;
193 }
194 if (size == 0) {
195 return NULL;
196 }
197 if (!s_inited) {
198 return NULL;
199 }
200 ch = &s_trace_channels[dest];
201 if (ch->hw == NULL) {
202 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
203 return NULL;
204 }
205 if (ch->hw->get_up_buffer == NULL) {
206 return NULL;
207 }
208
209 esp_apptrace_tmo_init(&tmo, user_tmo);
210 return ch->hw->get_up_buffer(ch->hw_data, size, &tmo);
211 }
212
esp_apptrace_buffer_put(esp_apptrace_dest_t dest,uint8_t * ptr,uint32_t user_tmo)213 esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo)
214 {
215 esp_apptrace_tmo_t tmo;
216 esp_apptrace_channel_t *ch;
217
218 ESP_APPTRACE_LOGV("%s(): enter", __func__);
219 if (dest >= ESP_APPTRACE_DEST_MAX) {
220 return ESP_ERR_INVALID_ARG;
221 }
222 if (ptr == NULL) {
223 return ESP_ERR_INVALID_ARG;
224 }
225 if (!s_inited) {
226 return ESP_ERR_INVALID_STATE;
227 }
228 ch = &s_trace_channels[dest];
229 if (ch->hw == NULL) {
230 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
231 return ESP_ERR_NOT_SUPPORTED;
232 }
233 if (ch->hw->put_up_buffer == NULL) {
234 return ESP_ERR_NOT_SUPPORTED;
235 }
236
237 esp_apptrace_tmo_init(&tmo, user_tmo);
238 return ch->hw->put_up_buffer(ch->hw_data, ptr, &tmo);
239 }
240
esp_apptrace_write(esp_apptrace_dest_t dest,const void * data,uint32_t size,uint32_t user_tmo)241 esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t user_tmo)
242 {
243 uint8_t *ptr = NULL;
244 esp_apptrace_tmo_t tmo;
245 esp_apptrace_channel_t *ch;
246
247 ESP_APPTRACE_LOGV("%s(): enter", __func__);
248 if (dest >= ESP_APPTRACE_DEST_MAX) {
249 return ESP_ERR_INVALID_ARG;
250 }
251 if (data == NULL || size == 0) {
252 return ESP_ERR_INVALID_ARG;
253 }
254 if (!s_inited) {
255 return ESP_ERR_INVALID_STATE;
256 }
257 ch = &s_trace_channels[dest];
258 if (ch->hw == NULL) {
259 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
260 return ESP_ERR_NOT_SUPPORTED;
261 }
262 if (ch->hw->get_up_buffer == NULL || ch->hw->put_up_buffer == NULL) {
263 return ESP_ERR_NOT_SUPPORTED;
264 }
265
266 esp_apptrace_tmo_init(&tmo, user_tmo);
267 ptr = ch->hw->get_up_buffer(ch->hw_data, size, &tmo);
268 if (ptr == NULL) {
269 return ESP_ERR_NO_MEM;
270 }
271
272 // actually can be suspended here by higher prio tasks/ISRs
273 //TODO: use own memcpy with dead trace calls kick-off algo and tmo expiration check
274 memcpy(ptr, data, size);
275
276 // now indicate that this buffer is ready to be sent off to host
277 return ch->hw->put_up_buffer(ch->hw_data, ptr, &tmo);
278 }
279
esp_apptrace_vprintf_to(esp_apptrace_dest_t dest,uint32_t user_tmo,const char * fmt,va_list ap)280 int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const char *fmt, va_list ap)
281 {
282 uint16_t nargs = 0;
283 uint8_t *pout, *p = (uint8_t *)fmt;
284 esp_apptrace_tmo_t tmo;
285 esp_apptrace_channel_t *ch;
286
287 ESP_APPTRACE_LOGV("%s(): enter", __func__);
288 if (dest >= ESP_APPTRACE_DEST_MAX) {
289 return -1;
290 }
291 if (fmt == NULL) {
292 return -1;
293 }
294 if (!s_inited) {
295 return -1;
296 }
297 ch = &s_trace_channels[dest];
298 if (ch->hw == NULL) {
299 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
300 return -1;
301 }
302 if (ch->hw->get_up_buffer == NULL || ch->hw->put_up_buffer == NULL) {
303 return -1;
304 }
305
306 esp_apptrace_tmo_init(&tmo, user_tmo);
307 ESP_APPTRACE_LOGD("fmt %x", fmt);
308 while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) {
309 p++;
310 if (*p != '%' && *p != 0) {
311 nargs++;
312 }
313 }
314 ESP_APPTRACE_LOGD("nargs = %d", nargs);
315 if (p) {
316 ESP_APPTRACE_LOGE("Failed to store all printf args!");
317 }
318
319 pout = ch->hw->get_up_buffer(ch->hw_data, 1 + sizeof(char *) + nargs * sizeof(uint32_t), &tmo);
320 if (pout == NULL) {
321 ESP_APPTRACE_LOGE("Failed to get buffer!");
322 return -1;
323 }
324 p = pout;
325 *pout = nargs;
326 pout++;
327 *(const char **)pout = fmt;
328 pout += sizeof(char *);
329 while (nargs-- > 0) {
330 uint32_t arg = va_arg(ap, uint32_t);
331 *(uint32_t *)pout = arg;
332 pout += sizeof(uint32_t);
333 ESP_APPTRACE_LOGD("arg %x", arg);
334 }
335
336 int ret = ch->hw->put_up_buffer(ch->hw_data, p, &tmo);
337 if (ret != ESP_OK) {
338 ESP_APPTRACE_LOGE("Failed to put printf buf (%d)!", ret);
339 return -1;
340 }
341
342 return (pout - p);
343 }
344
esp_apptrace_vprintf(const char * fmt,va_list ap)345 int esp_apptrace_vprintf(const char *fmt, va_list ap)
346 {
347 return esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_JTAG, 0, fmt, ap);
348 }
349
esp_apptrace_flush_nolock(esp_apptrace_dest_t dest,uint32_t min_sz,uint32_t usr_tmo)350 esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t usr_tmo)
351 {
352 esp_apptrace_tmo_t tmo;
353 esp_apptrace_channel_t *ch;
354
355 ESP_APPTRACE_LOGV("%s(): enter", __func__);
356 if (dest >= ESP_APPTRACE_DEST_MAX) {
357 return ESP_ERR_INVALID_ARG;
358 }
359 if (!s_inited) {
360 return ESP_ERR_INVALID_STATE;
361 }
362 ch = &s_trace_channels[dest];
363 if (ch->hw == NULL) {
364 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
365 return ESP_ERR_NOT_SUPPORTED;
366 }
367 if (ch->hw->flush_up_buffer_nolock == NULL) {
368 return ESP_ERR_NOT_SUPPORTED;
369 }
370
371 esp_apptrace_tmo_init(&tmo, usr_tmo);
372 return ch->hw->flush_up_buffer_nolock(ch->hw_data, min_sz, &tmo);
373 }
374
esp_apptrace_flush(esp_apptrace_dest_t dest,uint32_t usr_tmo)375 esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t usr_tmo)
376 {
377 esp_apptrace_tmo_t tmo;
378 esp_apptrace_channel_t *ch;
379
380 ESP_APPTRACE_LOGV("%s(): enter", __func__);
381 if (dest >= ESP_APPTRACE_DEST_MAX) {
382 return ESP_ERR_INVALID_ARG;
383 }
384 if (!s_inited) {
385 return ESP_ERR_INVALID_STATE;
386 }
387 ch = &s_trace_channels[dest];
388 if (ch->hw == NULL) {
389 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
390 return ESP_ERR_NOT_SUPPORTED;
391 }
392 if (ch->hw->flush_up_buffer == NULL) {
393 return ESP_ERR_NOT_SUPPORTED;
394 }
395
396 esp_apptrace_tmo_init(&tmo, usr_tmo);
397 return ch->hw->flush_up_buffer(ch->hw_data, &tmo);
398 }
399
esp_apptrace_host_is_connected(esp_apptrace_dest_t dest)400 bool esp_apptrace_host_is_connected(esp_apptrace_dest_t dest)
401 {
402 esp_apptrace_channel_t *ch;
403
404 ESP_APPTRACE_LOGV("%s(): enter", __func__);
405 if (dest >= ESP_APPTRACE_DEST_MAX) {
406 return false;
407 }
408 if (!s_inited) {
409 return false;
410 }
411 ch = &s_trace_channels[dest];
412 if (ch->hw == NULL) {
413 ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest);
414 return false;
415 }
416 if (ch->hw->host_is_connected == NULL) {
417 return false;
418 }
419
420 return ch->hw->host_is_connected(ch->hw_data);
421 }
422