cherrysh_port.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Copyright (c) 2024, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "event_groups.h"
  9. #include "csh.h"
  10. #include "usbd_core.h"
  11. #include "usbd_adb.h"
  12. #include "chry_ringbuffer.h"
  13. static chry_ringbuffer_t shell_rb;
  14. static uint8_t mempool[1024];
  15. #ifndef task_repl_PRIORITY
  16. #define task_repl_PRIORITY (configMAX_PRIORITIES - 4U)
  17. #endif
  18. #ifndef task_exec_PRIORITY
  19. #define task_exec_PRIORITY (configMAX_PRIORITIES - 5U)
  20. #endif
  21. static chry_shell_t csh;
  22. static volatile bool login = false;
  23. static StaticTask_t task_buffer_repl;
  24. static StaticTask_t task_buffer_exec;
  25. static StackType_t task_stack_repl[1024];
  26. static StackType_t task_stack_exec[1024];
  27. static TaskHandle_t task_hdl_repl = NULL;
  28. static TaskHandle_t task_hdl_exec = NULL;
  29. static EventGroupHandle_t event_hdl;
  30. static StaticEventGroup_t event_grp;
  31. void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len)
  32. {
  33. chry_ringbuffer_write(&shell_rb, data, len);
  34. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  35. xEventGroupSetBitsFromISR(event_hdl, 0x10, &xHigherPriorityTaskWoken);
  36. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  37. }
  38. void usbd_adb_notify_write_done(void)
  39. {
  40. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  41. xEventGroupSetBitsFromISR(event_hdl, 0x20, &xHigherPriorityTaskWoken);
  42. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  43. }
  44. static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size)
  45. {
  46. (void)rl;
  47. if (!usb_device_is_configured(0)) {
  48. return size;
  49. }
  50. if (usbd_adb_can_write() && size) {
  51. usbd_abd_write(ADB_SHELL_LOALID, data, size);
  52. xEventGroupWaitBits(event_hdl, 0x20, pdTRUE, pdFALSE, portMAX_DELAY);
  53. }
  54. return size;
  55. }
  56. static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size)
  57. {
  58. (void)rl;
  59. return chry_ringbuffer_read(&shell_rb, data, size);
  60. }
  61. static void wait_char(void)
  62. {
  63. EventBits_t event;
  64. wait:
  65. /* In order to lock the log from being disrupted , wait for REPL task execution to complete */
  66. event = xEventGroupWaitBits(event_hdl, (0x10 | 0x01 | 0x04), pdTRUE, pdFALSE, portMAX_DELAY);
  67. if ((event & 0x10) == 0) {
  68. if (event & 0x01) {
  69. chry_readline_erase_line(&csh.rl);
  70. xEventGroupSetBits(event_hdl, 0x02);
  71. }
  72. if (event & 0x04) {
  73. chry_readline_edit_refresh(&csh.rl);
  74. xEventGroupSetBits(event_hdl, 0x08);
  75. }
  76. goto wait;
  77. }
  78. }
  79. static void task_repl(void *param)
  80. {
  81. (void)param;
  82. int ret;
  83. volatile uint8_t *pexec = (void *)&csh.exec;
  84. for (;;) {
  85. restart:
  86. if (login) {
  87. goto repl;
  88. } else {
  89. }
  90. ret = csh_login(&csh);
  91. if (ret == 0) {
  92. login = true;
  93. } else if (ret == 1) {
  94. /*!< no enough char */
  95. wait_char();
  96. continue;
  97. } else {
  98. continue;
  99. }
  100. repl:
  101. ret = chry_shell_task_repl(&csh);
  102. if (ret == -1) {
  103. /*!< error */
  104. goto restart;
  105. } else if (ret == 1) {
  106. /*!< no enough char */
  107. wait_char();
  108. } else {
  109. /*!< restart */
  110. }
  111. /*!< check flag */
  112. if (*pexec == CSH_STATUS_EXEC_DONE) {
  113. *pexec = CSH_STATUS_EXEC_IDLE;
  114. chry_readline_auto_refresh(&csh.rl, true);
  115. chry_readline_ignore(&csh.rl, false);
  116. chry_readline_edit_refresh(&csh.rl);
  117. }
  118. if (login == false) {
  119. chry_readline_erase_line(&csh.rl);
  120. csh.rl.noblock = false;
  121. }
  122. }
  123. }
  124. static void task_exec(void *param)
  125. {
  126. (void)param;
  127. /*!< execute shell command */
  128. chry_shell_task_exec(&csh);
  129. /*!< notify REPL task execute done */
  130. xEventGroupSetBits(event_hdl, 0x10);
  131. /*!< wait for REPL task delete */
  132. vTaskSuspend(NULL);
  133. }
  134. int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv)
  135. {
  136. volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec;
  137. (void)csh;
  138. (void)argc;
  139. (void)argv;
  140. if (*p_task_hdl_exec != NULL) {
  141. vTaskDelete(*p_task_hdl_exec);
  142. }
  143. *p_task_hdl_exec = xTaskCreateStatic(task_exec, "task_exec", 1024U, NULL, task_exec_PRIORITY, task_stack_exec, &task_buffer_exec);
  144. return 0;
  145. }
  146. void chry_shell_port_default_handler(chry_shell_t *csh, int sig)
  147. {
  148. volatile uint8_t *pexec = (void *)&csh->exec;
  149. volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec;
  150. switch (sig) {
  151. case CSH_SIGINT:
  152. case CSH_SIGQUIT:
  153. case CSH_SIGKILL:
  154. case CSH_SIGTERM:
  155. break;
  156. default:
  157. return;
  158. }
  159. /*!< force delete task */
  160. if (*p_task_hdl_exec != NULL) {
  161. vTaskDelete(task_hdl_exec);
  162. *p_task_hdl_exec = NULL;
  163. }
  164. switch (sig) {
  165. case CSH_SIGINT:
  166. csh->rl.sput(&csh->rl, "^SIGINT" CONFIG_CSH_NEWLINE, sizeof("^SIGINT" CONFIG_CSH_NEWLINE) - 1);
  167. break;
  168. case CSH_SIGQUIT:
  169. csh->rl.sput(&csh->rl, "^SIGQUIT" CONFIG_CSH_NEWLINE, sizeof("^SIGQUIT" CONFIG_CSH_NEWLINE) - 1);
  170. break;
  171. case CSH_SIGKILL:
  172. csh->rl.sput(&csh->rl, "^SIGKILL" CONFIG_CSH_NEWLINE, sizeof("^SIGKILL" CONFIG_CSH_NEWLINE) - 1);
  173. break;
  174. case CSH_SIGTERM:
  175. csh->rl.sput(&csh->rl, "^SIGTERM" CONFIG_CSH_NEWLINE, sizeof("^SIGTERM" CONFIG_CSH_NEWLINE) - 1);
  176. break;
  177. default:
  178. return;
  179. }
  180. *pexec = CSH_STATUS_EXEC_IDLE;
  181. chry_readline_auto_refresh(&csh->rl, true);
  182. chry_readline_ignore(&csh->rl, false);
  183. chry_readline_edit_refresh(&csh->rl);
  184. }
  185. int shell_init(bool need_login)
  186. {
  187. chry_shell_init_t csh_init;
  188. if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) {
  189. return -1;
  190. }
  191. if (need_login) {
  192. login = false;
  193. } else {
  194. login = true;
  195. }
  196. /*!< I/O callback */
  197. csh_init.sput = csh_sput_cb;
  198. csh_init.sget = csh_sget_cb;
  199. #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB
  200. extern const int __fsymtab_start;
  201. extern const int __fsymtab_end;
  202. extern const int __vsymtab_start;
  203. extern const int __vsymtab_end;
  204. /*!< get table from ld symbol */
  205. csh_init.command_table_beg = &__fsymtab_start;
  206. csh_init.command_table_end = &__fsymtab_end;
  207. csh_init.variable_table_beg = &__vsymtab_start;
  208. csh_init.variable_table_end = &__vsymtab_end;
  209. #endif
  210. #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
  211. static char csh_prompt_buffer[128];
  212. /*!< set prompt buffer */
  213. csh_init.prompt_buffer = csh_prompt_buffer;
  214. csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer);
  215. #endif
  216. #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY
  217. static char csh_history_buffer[128];
  218. /*!< set history buffer */
  219. csh_init.history_buffer = csh_history_buffer;
  220. csh_init.history_buffer_size = sizeof(csh_history_buffer);
  221. #endif
  222. #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC
  223. static char csh_line_buffer[128];
  224. /*!< set linebuffer */
  225. csh_init.line_buffer = csh_line_buffer;
  226. csh_init.line_buffer_size = sizeof(csh_line_buffer);
  227. #endif
  228. csh_init.uid = 0;
  229. csh_init.user[0] = "cherry";
  230. /*!< The port hash function is required,
  231. and the strcmp attribute is used weakly by default,
  232. int chry_shell_port_hash_strcmp(const char *hash, const char *str); */
  233. csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */
  234. csh_init.host = "cherryadb";
  235. csh_init.user_data = NULL;
  236. int ret = chry_shell_init(&csh, &csh_init);
  237. if (ret) {
  238. return -1;
  239. }
  240. task_hdl_exec = NULL;
  241. event_hdl = xEventGroupCreateStatic(&event_grp);
  242. task_hdl_repl = xTaskCreateStatic(task_repl, "task_repl", 1024U, NULL, task_repl_PRIORITY, task_stack_repl, &task_buffer_repl);
  243. return 0;
  244. }
  245. void shell_lock(void)
  246. {
  247. xEventGroupSetBits(event_hdl, 0x01);
  248. xEventGroupWaitBits(event_hdl, 0x02, pdTRUE, pdTRUE, portMAX_DELAY);
  249. }
  250. void shell_unlock(void)
  251. {
  252. xEventGroupSetBits(event_hdl, 0x04);
  253. xEventGroupWaitBits(event_hdl, 0x08, pdTRUE, pdTRUE, portMAX_DELAY);
  254. }
  255. static int csh_exit(int argc, char **argv)
  256. {
  257. (void)argc;
  258. (void)argv;
  259. usbd_adb_close(ADB_SHELL_LOALID);
  260. return 0;
  261. }
  262. CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, );
  263. #define __ENV_PATH "/sbin:/bin"
  264. const char ENV_PATH[] = __ENV_PATH;
  265. CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH));
  266. #define __ENV_ZERO ""
  267. const char ENV_ZERO[] = __ENV_ZERO;
  268. CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO));