host_file_io.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. #include <string.h>
  17. #include "esp_app_trace.h"
  18. #if CONFIG_APPTRACE_ENABLE
  19. #include "esp_log.h"
  20. const static char *TAG = "esp_host_file_io";
  21. #define ESP_APPTRACE_FILE_CMD_FOPEN 0x0
  22. #define ESP_APPTRACE_FILE_CMD_FCLOSE 0x1
  23. #define ESP_APPTRACE_FILE_CMD_FWRITE 0x2
  24. #define ESP_APPTRACE_FILE_CMD_FREAD 0x3
  25. #define ESP_APPTRACE_FILE_CMD_FSEEK 0x4
  26. #define ESP_APPTRACE_FILE_CMD_FTELL 0x5
  27. #define ESP_APPTRACE_FILE_CMD_STOP 0x6 // indicates that there is no files to transfer
  28. /** File operation header */
  29. typedef struct {
  30. uint8_t cmd; ///< Command ID
  31. } esp_apptrace_fcmd_hdr_t;
  32. /** Helper structure for fopen */
  33. typedef struct {
  34. const char *path;
  35. uint16_t path_len;
  36. const char *mode;
  37. uint16_t mode_len;
  38. } esp_apptrace_fopen_args_t;
  39. /** Helper structure for fclose */
  40. typedef struct {
  41. void *file;
  42. } esp_apptrace_fclose_args_t;
  43. /** Helper structure for fwrite */
  44. typedef struct {
  45. void * buf;
  46. size_t size;
  47. void * file;
  48. } esp_apptrace_fwrite_args_t;
  49. /** Helper structure for fread */
  50. typedef struct {
  51. size_t size;
  52. void * file;
  53. } esp_apptrace_fread_args_t;
  54. /** Helper structure for fseek */
  55. typedef struct {
  56. long offset;
  57. int whence;
  58. void * file;
  59. } esp_apptrace_fseek_args_t;
  60. /** Helper structure for ftell */
  61. typedef struct {
  62. void *file;
  63. } esp_apptrace_ftell_args_t;
  64. 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)
  65. {
  66. esp_err_t ret;
  67. esp_apptrace_fcmd_hdr_t *hdr;
  68. ESP_EARLY_LOGV(TAG, "%s %d", __func__, cmd);
  69. uint8_t *ptr = esp_apptrace_buffer_get(dest, sizeof(*hdr) + args_len, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
  70. if (ptr == NULL) {
  71. return ESP_ERR_NO_MEM;
  72. }
  73. hdr = (esp_apptrace_fcmd_hdr_t *)ptr;
  74. hdr->cmd = cmd;
  75. if (prep_args) {
  76. prep_args(ptr + sizeof(hdr->cmd), args);
  77. }
  78. // now indicate that this buffer is ready to be sent off to host
  79. ret = esp_apptrace_buffer_put(dest, ptr, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
  80. if (ret != ESP_OK) {
  81. ESP_EARLY_LOGE(TAG, "Failed to put apptrace buffer (%d)!", ret);
  82. return ret;
  83. }
  84. ret = esp_apptrace_flush(dest, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
  85. if (ret != ESP_OK) {
  86. ESP_EARLY_LOGE(TAG, "Failed to flush apptrace buffer (%d)!", ret);
  87. return ret;
  88. }
  89. return ESP_OK;
  90. }
  91. static esp_err_t esp_apptrace_file_rsp_recv(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t buf_len)
  92. {
  93. uint32_t tot_rd = 0;
  94. while (tot_rd < buf_len) {
  95. uint32_t rd_size = buf_len - tot_rd;
  96. esp_err_t ret = esp_apptrace_read(dest, buf + tot_rd, &rd_size, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
  97. if (ret != ESP_OK) {
  98. ESP_EARLY_LOGE(TAG, "Failed to read (%d)!", ret);
  99. return ret;
  100. }
  101. ESP_EARLY_LOGV(TAG, "%s read %d bytes", __FUNCTION__, rd_size);
  102. tot_rd += rd_size;
  103. }
  104. return ESP_OK;
  105. }
  106. static void esp_apptrace_fopen_args_prepare(uint8_t *buf, void *priv)
  107. {
  108. esp_apptrace_fopen_args_t *args = priv;
  109. memcpy(buf, args->path, args->path_len);
  110. memcpy(buf + args->path_len, args->mode, args->mode_len);
  111. }
  112. void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode)
  113. {
  114. esp_apptrace_fopen_args_t cmd_args;
  115. ESP_EARLY_LOGV(TAG, "esp_apptrace_fopen '%s' '%s'", path, mode);
  116. if (path == NULL || mode == NULL) {
  117. return 0;
  118. }
  119. cmd_args.path = path;
  120. cmd_args.path_len = strlen(path) + 1;
  121. cmd_args.mode = mode;
  122. cmd_args.mode_len = strlen(mode) + 1;
  123. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FOPEN, esp_apptrace_fopen_args_prepare,
  124. &cmd_args, cmd_args.path_len+cmd_args.mode_len);
  125. if (ret != ESP_OK) {
  126. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  127. return NULL;
  128. }
  129. // now read the answer
  130. void *resp;
  131. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  132. if (ret != ESP_OK) {
  133. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  134. return NULL;
  135. }
  136. return resp;
  137. }
  138. static void esp_apptrace_fclose_args_prepare(uint8_t *buf, void *priv)
  139. {
  140. esp_apptrace_fclose_args_t *args = priv;
  141. memcpy(buf, &args->file, sizeof(args->file));
  142. }
  143. int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream)
  144. {
  145. esp_apptrace_fclose_args_t cmd_args;
  146. cmd_args.file = stream;
  147. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FCLOSE, esp_apptrace_fclose_args_prepare,
  148. &cmd_args, sizeof(cmd_args));
  149. if (ret != ESP_OK) {
  150. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  151. return EOF;
  152. }
  153. // now read the answer
  154. int resp;
  155. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  156. if (ret != ESP_OK) {
  157. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  158. return EOF;
  159. }
  160. return resp;
  161. }
  162. static void esp_apptrace_fwrite_args_prepare(uint8_t *buf, void *priv)
  163. {
  164. esp_apptrace_fwrite_args_t *args = priv;
  165. memcpy(buf, &args->file, sizeof(args->file));
  166. memcpy(buf + sizeof(args->file), args->buf, args->size);
  167. }
  168. size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream)
  169. {
  170. esp_apptrace_fwrite_args_t cmd_args;
  171. ESP_EARLY_LOGV(TAG, "esp_apptrace_fwrite f %p l %d", stream, size*nmemb);
  172. if (ptr == NULL) {
  173. return 0;
  174. }
  175. cmd_args.buf = (void *)ptr;
  176. cmd_args.size = size * nmemb;
  177. cmd_args.file = stream;
  178. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FWRITE, esp_apptrace_fwrite_args_prepare,
  179. &cmd_args, sizeof(cmd_args.file)+cmd_args.size);
  180. if (ret != ESP_OK) {
  181. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  182. return 0;
  183. }
  184. // now read the answer
  185. size_t resp;
  186. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  187. if (ret != ESP_OK) {
  188. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  189. return 0;
  190. }
  191. return resp;
  192. }
  193. static void esp_apptrace_fread_args_prepare(uint8_t *buf, void *priv)
  194. {
  195. esp_apptrace_fread_args_t *args = priv;
  196. memcpy(buf, &args->file, sizeof(args->file));
  197. memcpy(buf + sizeof(args->file), &args->size, sizeof(args->size));
  198. }
  199. size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream)
  200. {
  201. esp_apptrace_fread_args_t cmd_args;
  202. ESP_EARLY_LOGV(TAG, "esp_apptrace_fread f %p l %d", stream, size*nmemb);
  203. if (ptr == NULL) {
  204. return 0;
  205. }
  206. cmd_args.size = size * nmemb;
  207. cmd_args.file = stream;
  208. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare,
  209. &cmd_args, sizeof(cmd_args));
  210. if (ret != ESP_OK) {
  211. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  212. return 0;
  213. }
  214. // now read the answer
  215. size_t resp;
  216. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  217. if (ret != ESP_OK) {
  218. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  219. return 0;
  220. }
  221. if (resp > 0) {
  222. ret = esp_apptrace_file_rsp_recv(dest, ptr, resp);
  223. if (ret != ESP_OK) {
  224. ESP_EARLY_LOGE(TAG, "Failed to read file data (%d)!", ret);
  225. return 0;
  226. }
  227. }
  228. return resp;
  229. }
  230. static void esp_apptrace_fseek_args_prepare(uint8_t *buf, void *priv)
  231. {
  232. esp_apptrace_fseek_args_t *args = priv;
  233. memcpy(buf, &args->file, sizeof(args->file));
  234. memcpy(buf + sizeof(args->file), &args->offset, sizeof(args->offset));
  235. memcpy(buf + sizeof(args->file) + sizeof(args->offset), &args->whence, sizeof(args->whence));
  236. }
  237. int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence)
  238. {
  239. esp_apptrace_fseek_args_t cmd_args;
  240. ESP_EARLY_LOGV(TAG, "esp_apptrace_fseek f %p o 0x%lx w %d", stream, offset, whence);
  241. cmd_args.file = stream;
  242. cmd_args.offset = offset;
  243. cmd_args.whence = whence;
  244. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FSEEK, esp_apptrace_fseek_args_prepare,
  245. &cmd_args, sizeof(cmd_args));
  246. if (ret != ESP_OK) {
  247. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  248. return -1;
  249. }
  250. // now read the answer
  251. int resp;
  252. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  253. if (ret != ESP_OK) {
  254. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  255. return -1;
  256. }
  257. return resp;
  258. }
  259. static void esp_apptrace_ftell_args_prepare(uint8_t *buf, void *priv)
  260. {
  261. esp_apptrace_ftell_args_t *args = priv;
  262. memcpy(buf, &args->file, sizeof(args->file));
  263. }
  264. int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream)
  265. {
  266. esp_apptrace_ftell_args_t cmd_args;
  267. cmd_args.file = stream;
  268. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FTELL, esp_apptrace_ftell_args_prepare,
  269. &cmd_args, sizeof(cmd_args));
  270. if (ret != ESP_OK) {
  271. ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
  272. return -1;
  273. }
  274. // now read the answer
  275. int resp;
  276. ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
  277. if (ret != ESP_OK) {
  278. ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
  279. return -1;
  280. }
  281. return resp;
  282. }
  283. int esp_apptrace_fstop(esp_apptrace_dest_t dest)
  284. {
  285. ESP_EARLY_LOGV(TAG, "%s", __func__);
  286. esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_STOP, NULL, NULL, 0);
  287. if (ret != ESP_OK) {
  288. ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
  289. }
  290. return ret;
  291. }
  292. #endif