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