1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 //
7 // Hot It Works
8 // ************
9 //
10 // This module implements host file I/O protocol on top of apptrace module.
11 // The protocol is enough simple. It sends command with arguments to the host and receives response from it.
12 // Responses contains return values of respective file I/O API. This value is returned to the caller.
13 // Commands has the following format:
14 // * Header. See esp_apptrace_fcmd_hdr_t.
15 // * Operation arguments. See file operation helper structures below.
16
17 #include <string.h>
18 #include "esp_app_trace.h"
19
20 #if CONFIG_APPTRACE_ENABLE
21
22 #include "esp_log.h"
23 const static char *TAG = "esp_host_file_io";
24
25 #define ESP_APPTRACE_FILE_CMD_FOPEN 0x0
26 #define ESP_APPTRACE_FILE_CMD_FCLOSE 0x1
27 #define ESP_APPTRACE_FILE_CMD_FWRITE 0x2
28 #define ESP_APPTRACE_FILE_CMD_FREAD 0x3
29 #define ESP_APPTRACE_FILE_CMD_FSEEK 0x4
30 #define ESP_APPTRACE_FILE_CMD_FTELL 0x5
31 #define ESP_APPTRACE_FILE_CMD_STOP 0x6 // indicates that there is no files to transfer
32
33 /** File operation header */
34 typedef struct {
35 uint8_t cmd; ///< Command ID
36 } esp_apptrace_fcmd_hdr_t;
37
38 /** Helper structure for fopen */
39 typedef struct {
40 const char *path;
41 uint16_t path_len;
42 const char *mode;
43 uint16_t mode_len;
44 } esp_apptrace_fopen_args_t;
45
46 /** Helper structure for fclose */
47 typedef struct {
48 void *file;
49 } esp_apptrace_fclose_args_t;
50
51 /** Helper structure for fwrite */
52 typedef struct {
53 void * buf;
54 size_t size;
55 void * file;
56 } esp_apptrace_fwrite_args_t;
57
58 /** Helper structure for fread */
59 typedef struct {
60 size_t size;
61 void * file;
62 } esp_apptrace_fread_args_t;
63
64 /** Helper structure for fseek */
65 typedef struct {
66 long offset;
67 int whence;
68 void * file;
69 } esp_apptrace_fseek_args_t;
70
71 /** Helper structure for ftell */
72 typedef struct {
73 void *file;
74 } esp_apptrace_ftell_args_t;
75
esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest,uint8_t cmd,void (* prep_args)(uint8_t *,void *),void * args,uint32_t args_len)76 static esp_err_t esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest, uint8_t cmd, void (*prep_args)(uint8_t *, void *), void *args, uint32_t args_len)
77 {
78 esp_err_t ret;
79 esp_apptrace_fcmd_hdr_t *hdr;
80
81 ESP_EARLY_LOGV(TAG, "%s %d", __func__, cmd);
82 uint8_t *ptr = esp_apptrace_buffer_get(dest, sizeof(*hdr) + args_len, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
83 if (ptr == NULL) {
84 return ESP_ERR_NO_MEM;
85 }
86
87 hdr = (esp_apptrace_fcmd_hdr_t *)ptr;
88 hdr->cmd = cmd;
89 if (prep_args) {
90 prep_args(ptr + sizeof(hdr->cmd), args);
91 }
92
93 // now indicate that this buffer is ready to be sent off to host
94 ret = esp_apptrace_buffer_put(dest, ptr, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
95 if (ret != ESP_OK) {
96 ESP_EARLY_LOGE(TAG, "Failed to put apptrace buffer (%d)!", ret);
97 return ret;
98 }
99
100 ret = esp_apptrace_flush(dest, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
101 if (ret != ESP_OK) {
102 ESP_EARLY_LOGE(TAG, "Failed to flush apptrace buffer (%d)!", ret);
103 return ret;
104 }
105
106 return ESP_OK;
107 }
108
esp_apptrace_file_rsp_recv(esp_apptrace_dest_t dest,uint8_t * buf,uint32_t buf_len)109 static esp_err_t esp_apptrace_file_rsp_recv(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t buf_len)
110 {
111 uint32_t tot_rd = 0;
112 while (tot_rd < buf_len) {
113 uint32_t rd_size = buf_len - tot_rd;
114 esp_err_t ret = esp_apptrace_read(dest, buf + tot_rd, &rd_size, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
115 if (ret != ESP_OK) {
116 ESP_EARLY_LOGE(TAG, "Failed to read (%d)!", ret);
117 return ret;
118 }
119 ESP_EARLY_LOGV(TAG, "%s read %d bytes", __FUNCTION__, rd_size);
120 tot_rd += rd_size;
121 }
122
123 return ESP_OK;
124 }
125
esp_apptrace_fopen_args_prepare(uint8_t * buf,void * priv)126 static void esp_apptrace_fopen_args_prepare(uint8_t *buf, void *priv)
127 {
128 esp_apptrace_fopen_args_t *args = priv;
129
130 memcpy(buf, args->path, args->path_len);
131 memcpy(buf + args->path_len, args->mode, args->mode_len);
132 }
133
esp_apptrace_fopen(esp_apptrace_dest_t dest,const char * path,const char * mode)134 void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode)
135 {
136 esp_apptrace_fopen_args_t cmd_args;
137
138 ESP_EARLY_LOGV(TAG, "esp_apptrace_fopen '%s' '%s'", path, mode);
139 if (path == NULL || mode == NULL) {
140 return 0;
141 }
142
143 cmd_args.path = path;
144 cmd_args.path_len = strlen(path) + 1;
145 cmd_args.mode = mode;
146 cmd_args.mode_len = strlen(mode) + 1;
147
148 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FOPEN, esp_apptrace_fopen_args_prepare,
149 &cmd_args, cmd_args.path_len+cmd_args.mode_len);
150 if (ret != ESP_OK) {
151 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
152 return NULL;
153 }
154
155 // now read the answer
156 void *resp;
157 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
158 if (ret != ESP_OK) {
159 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
160 return NULL;
161 }
162
163 return resp;
164 }
165
esp_apptrace_fclose_args_prepare(uint8_t * buf,void * priv)166 static void esp_apptrace_fclose_args_prepare(uint8_t *buf, void *priv)
167 {
168 esp_apptrace_fclose_args_t *args = priv;
169
170 memcpy(buf, &args->file, sizeof(args->file));
171 }
172
esp_apptrace_fclose(esp_apptrace_dest_t dest,void * stream)173 int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream)
174 {
175 esp_apptrace_fclose_args_t cmd_args;
176
177 cmd_args.file = stream;
178 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FCLOSE, esp_apptrace_fclose_args_prepare,
179 &cmd_args, sizeof(cmd_args));
180 if (ret != ESP_OK) {
181 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
182 return EOF;
183 }
184
185 // now read the answer
186 int resp;
187 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
188 if (ret != ESP_OK) {
189 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
190 return EOF;
191 }
192
193 return resp;
194 }
195
esp_apptrace_fwrite_args_prepare(uint8_t * buf,void * priv)196 static void esp_apptrace_fwrite_args_prepare(uint8_t *buf, void *priv)
197 {
198 esp_apptrace_fwrite_args_t *args = priv;
199
200 memcpy(buf, &args->file, sizeof(args->file));
201 memcpy(buf + sizeof(args->file), args->buf, args->size);
202 }
203
esp_apptrace_fwrite(esp_apptrace_dest_t dest,const void * ptr,size_t size,size_t nmemb,void * stream)204 size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream)
205 {
206 esp_apptrace_fwrite_args_t cmd_args;
207
208 ESP_EARLY_LOGV(TAG, "esp_apptrace_fwrite f %p l %d", stream, size*nmemb);
209
210 if (ptr == NULL) {
211 return 0;
212 }
213
214 cmd_args.buf = (void *)ptr;
215 cmd_args.size = size * nmemb;
216 cmd_args.file = stream;
217 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FWRITE, esp_apptrace_fwrite_args_prepare,
218 &cmd_args, sizeof(cmd_args.file)+cmd_args.size);
219 if (ret != ESP_OK) {
220 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
221 return 0;
222 }
223
224 // now read the answer
225 size_t resp;
226 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
227 if (ret != ESP_OK) {
228 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
229 return 0;
230 }
231
232 return resp;
233 }
234
esp_apptrace_fread_args_prepare(uint8_t * buf,void * priv)235 static void esp_apptrace_fread_args_prepare(uint8_t *buf, void *priv)
236 {
237 esp_apptrace_fread_args_t *args = priv;
238
239 memcpy(buf, &args->file, sizeof(args->file));
240 memcpy(buf + sizeof(args->file), &args->size, sizeof(args->size));
241 }
242
esp_apptrace_fread(esp_apptrace_dest_t dest,void * ptr,size_t size,size_t nmemb,void * stream)243 size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream)
244 {
245 esp_apptrace_fread_args_t cmd_args;
246
247 ESP_EARLY_LOGV(TAG, "esp_apptrace_fread f %p l %d", stream, size*nmemb);
248
249 if (ptr == NULL) {
250 return 0;
251 }
252
253 cmd_args.size = size * nmemb;
254 cmd_args.file = stream;
255 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare,
256 &cmd_args, sizeof(cmd_args));
257 if (ret != ESP_OK) {
258 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
259 return 0;
260 }
261
262 // now read the answer
263 size_t resp;
264 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
265 if (ret != ESP_OK) {
266 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
267 return 0;
268 }
269 if (resp > 0) {
270 ret = esp_apptrace_file_rsp_recv(dest, ptr, resp);
271 if (ret != ESP_OK) {
272 ESP_EARLY_LOGE(TAG, "Failed to read file data (%d)!", ret);
273 return 0;
274 }
275 }
276 return resp;
277 }
278
esp_apptrace_fseek_args_prepare(uint8_t * buf,void * priv)279 static void esp_apptrace_fseek_args_prepare(uint8_t *buf, void *priv)
280 {
281 esp_apptrace_fseek_args_t *args = priv;
282
283 memcpy(buf, &args->file, sizeof(args->file));
284 memcpy(buf + sizeof(args->file), &args->offset, sizeof(args->offset));
285 memcpy(buf + sizeof(args->file) + sizeof(args->offset), &args->whence, sizeof(args->whence));
286 }
287
esp_apptrace_fseek(esp_apptrace_dest_t dest,void * stream,long offset,int whence)288 int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence)
289 {
290 esp_apptrace_fseek_args_t cmd_args;
291
292 ESP_EARLY_LOGV(TAG, "esp_apptrace_fseek f %p o 0x%lx w %d", stream, offset, whence);
293
294 cmd_args.file = stream;
295 cmd_args.offset = offset;
296 cmd_args.whence = whence;
297 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FSEEK, esp_apptrace_fseek_args_prepare,
298 &cmd_args, sizeof(cmd_args));
299 if (ret != ESP_OK) {
300 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
301 return -1;
302 }
303
304 // now read the answer
305 int resp;
306 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
307 if (ret != ESP_OK) {
308 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
309 return -1;
310 }
311
312 return resp;
313 }
314
esp_apptrace_ftell_args_prepare(uint8_t * buf,void * priv)315 static void esp_apptrace_ftell_args_prepare(uint8_t *buf, void *priv)
316 {
317 esp_apptrace_ftell_args_t *args = priv;
318
319 memcpy(buf, &args->file, sizeof(args->file));
320 }
321
esp_apptrace_ftell(esp_apptrace_dest_t dest,void * stream)322 int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream)
323 {
324 esp_apptrace_ftell_args_t cmd_args;
325
326 cmd_args.file = stream;
327 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FTELL, esp_apptrace_ftell_args_prepare,
328 &cmd_args, sizeof(cmd_args));
329 if (ret != ESP_OK) {
330 ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
331 return -1;
332 }
333
334 // now read the answer
335 int resp;
336 ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
337 if (ret != ESP_OK) {
338 ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
339 return -1;
340 }
341
342 return resp;
343 }
344
esp_apptrace_fstop(esp_apptrace_dest_t dest)345 int esp_apptrace_fstop(esp_apptrace_dest_t dest)
346 {
347 ESP_EARLY_LOGV(TAG, "%s", __func__);
348 esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_STOP, NULL, NULL, 0);
349 if (ret != ESP_OK) {
350 ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
351 }
352 return ret;
353 }
354
355 #endif
356