cli_control.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #include "cli_control.h"
  2. #include <cli/cli.h>
  3. #include <cli/cli_i.h>
  4. #include <cli/cli_vcp.h>
  5. #include "cligui_main_i.h"
  6. #include <FreeRTOS.h>
  7. volatile bool gotCallbackSet = false;
  8. FuriStreamBuffer* tx_stream;
  9. FuriStreamBuffer* rx_stream;
  10. static FuriThread* volatile cliThread = NULL;
  11. static void tx_handler_stdout(const char* buffer, size_t size) {
  12. furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
  13. }
  14. static void tx_handler(const uint8_t* buffer, size_t size) {
  15. furi_thread_set_stdout_callback(tx_handler_stdout);
  16. cliThread = furi_thread_get_current();
  17. furi_stream_buffer_send(tx_stream, buffer, size, FuriWaitForever);
  18. }
  19. static size_t real_rx_handler(uint8_t* buffer, size_t size, uint32_t timeout) {
  20. size_t rx_cnt = 0;
  21. while(size > 0) {
  22. size_t batch_size = size;
  23. if(batch_size > 128) batch_size = 128;
  24. size_t len = furi_stream_buffer_receive(rx_stream, buffer, batch_size, timeout);
  25. if(len == 0) break;
  26. size -= len;
  27. buffer += len;
  28. rx_cnt += len;
  29. }
  30. return rx_cnt;
  31. }
  32. static CliCommand_internal* getInternalCliCommand(Cli* cli, const char* name) {
  33. FuriString* target_command = furi_string_alloc();
  34. furi_string_set_str(target_command, name);
  35. CliCommand_internal* command =
  36. CliCommandTree_internal_get(((Cli_internal*)cli)->commands, target_command);
  37. furi_string_free(target_command);
  38. return command;
  39. }
  40. static void session_init(void) {
  41. }
  42. static void session_deinit(void) {
  43. }
  44. static bool session_connected(void) {
  45. return true;
  46. }
  47. static CliSession session;
  48. void latch_tx_handler() {
  49. Cli* global_cli = furi_record_open(RECORD_CLI);
  50. CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
  51. cliThread = help_command->context;
  52. furi_thread_set_stdout_callback(tx_handler_stdout);
  53. if(cliThread != NULL) {
  54. ((FuriThread_internal*)cliThread)->output.write_callback = &tx_handler_stdout;
  55. }
  56. rx_stream = furi_stream_buffer_alloc(128, 1);
  57. tx_stream = furi_stream_buffer_alloc(128, 1);
  58. session.tx = &tx_handler;
  59. session.rx = &real_rx_handler;
  60. session.tx_stdout = &tx_handler_stdout;
  61. session.init = &session_init;
  62. session.deinit = &session_deinit;
  63. session.is_connected = &session_connected;
  64. cli_session_close(global_cli);
  65. cli_session_open(global_cli, &session);
  66. furi_record_close(RECORD_CLI);
  67. }
  68. void unlatch_tx_handler(bool persist) {
  69. Cli* global_cli = furi_record_open(RECORD_CLI);
  70. // Stash cliThread if not null
  71. if(cliThread != NULL) {
  72. CliCommand_internal* help_command = getInternalCliCommand(global_cli, "help");
  73. help_command->context = cliThread;
  74. }
  75. // Switch to new session
  76. if(persist) {
  77. // Use dummy debug firmware function as is_connected
  78. cli_vcp.is_connected = &furi_hal_version_do_i_belong_here;
  79. } else {
  80. // Send CTRL-C
  81. char eot = 0x03;
  82. furi_stream_buffer_send(rx_stream, &eot, 1, FuriWaitForever);
  83. }
  84. cli_session_open(global_cli, &cli_vcp);
  85. furi_record_close(RECORD_CLI);
  86. // Unblock waiting rx handler
  87. furi_stream_buffer_send(rx_stream, "_", 1, FuriWaitForever);
  88. // Reconfigure stdout_callback to cli_vcp
  89. if(cliThread != NULL) {
  90. ((FuriThread_internal*)cliThread)->output.write_callback = cli_vcp.tx_stdout;
  91. }
  92. // At this point, all cli_vcp functions should be back.
  93. furi_stream_buffer_free(rx_stream);
  94. furi_stream_buffer_free(tx_stream);
  95. }