rpc_app.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include "flipper.pb.h"
  2. #include <core/record.h>
  3. #include "rpc_i.h"
  4. #include <furi.h>
  5. #include <loader/loader.h>
  6. #include "rpc_app.h"
  7. #define TAG "RpcSystemApp"
  8. #define APP_BUTTON_TIMEOUT 1000
  9. struct RpcAppSystem {
  10. RpcSession* session;
  11. RpcAppSystemCallback app_callback;
  12. void* app_context;
  13. FuriTimer* timer;
  14. };
  15. static void rpc_system_app_timer_callback(void* context) {
  16. furi_assert(context);
  17. RpcAppSystem* rpc_app = context;
  18. if(rpc_app->app_callback) {
  19. rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context);
  20. }
  21. }
  22. static void rpc_system_app_start_process(const PB_Main* request, void* context) {
  23. furi_assert(request);
  24. furi_assert(context);
  25. furi_assert(request->which_content == PB_Main_app_start_request_tag);
  26. RpcAppSystem* rpc_app = context;
  27. RpcSession* session = rpc_app->session;
  28. furi_assert(session);
  29. char args_temp[16];
  30. FURI_LOG_D(TAG, "Start");
  31. PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START;
  32. Loader* loader = furi_record_open("loader");
  33. const char* app_name = request->content.app_start_request.name;
  34. if(app_name) {
  35. const char* app_args = request->content.app_start_request.args;
  36. if(strcmp(app_args, "RPC") == 0) {
  37. // If app is being started in RPC mode - pass RPC context via args string
  38. snprintf(args_temp, 16, "RPC %08lX", (uint32_t)rpc_app);
  39. app_args = args_temp;
  40. }
  41. LoaderStatus status = loader_start(loader, app_name, app_args);
  42. if(status == LoaderStatusErrorAppStarted) {
  43. result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED;
  44. } else if(status == LoaderStatusErrorInternal) {
  45. result = PB_CommandStatus_ERROR_APP_CANT_START;
  46. } else if(status == LoaderStatusErrorUnknownApp) {
  47. result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
  48. } else if(status == LoaderStatusOk) {
  49. result = PB_CommandStatus_OK;
  50. } else {
  51. furi_assert(0);
  52. }
  53. } else {
  54. result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
  55. }
  56. furi_record_close("loader");
  57. rpc_send_and_release_empty(session, request->command_id, result);
  58. }
  59. static void rpc_system_app_lock_status_process(const PB_Main* request, void* context) {
  60. furi_assert(request);
  61. furi_assert(context);
  62. furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
  63. RpcAppSystem* rpc_app = context;
  64. RpcSession* session = rpc_app->session;
  65. furi_assert(session);
  66. FURI_LOG_D(TAG, "LockStatus");
  67. Loader* loader = furi_record_open("loader");
  68. PB_Main response = {
  69. .has_next = false,
  70. .command_status = PB_CommandStatus_OK,
  71. .command_id = request->command_id,
  72. .which_content = PB_Main_app_lock_status_response_tag,
  73. };
  74. response.content.app_lock_status_response.locked = loader_is_locked(loader);
  75. furi_record_close("loader");
  76. rpc_send_and_release(session, &response);
  77. pb_release(&PB_Main_msg, &response);
  78. }
  79. static void rpc_system_app_exit(const PB_Main* request, void* context) {
  80. furi_assert(request);
  81. furi_assert(context);
  82. furi_assert(request->which_content == PB_Main_app_exit_request_tag);
  83. RpcAppSystem* rpc_app = context;
  84. RpcSession* session = rpc_app->session;
  85. furi_assert(session);
  86. PB_CommandStatus status;
  87. if(rpc_app->app_callback) {
  88. if(rpc_app->app_callback(RpcAppEventAppExit, NULL, rpc_app->app_context)) {
  89. status = PB_CommandStatus_OK;
  90. furi_timer_stop(rpc_app->timer);
  91. } else {
  92. status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
  93. }
  94. } else {
  95. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  96. }
  97. rpc_send_and_release_empty(session, request->command_id, status);
  98. }
  99. static void rpc_system_app_load_file(const PB_Main* request, void* context) {
  100. furi_assert(request);
  101. furi_assert(context);
  102. furi_assert(request->which_content == PB_Main_app_load_file_request_tag);
  103. RpcAppSystem* rpc_app = context;
  104. RpcSession* session = rpc_app->session;
  105. furi_assert(session);
  106. PB_CommandStatus status;
  107. if(rpc_app->app_callback) {
  108. const char* file_path = request->content.app_load_file_request.path;
  109. if(rpc_app->app_callback(RpcAppEventLoadFile, file_path, rpc_app->app_context)) {
  110. status = PB_CommandStatus_OK;
  111. } else {
  112. status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
  113. }
  114. } else {
  115. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  116. }
  117. rpc_send_and_release_empty(session, request->command_id, status);
  118. }
  119. static void rpc_system_app_button_press(const PB_Main* request, void* context) {
  120. furi_assert(request);
  121. furi_assert(context);
  122. furi_assert(request->which_content == PB_Main_app_button_press_request_tag);
  123. RpcAppSystem* rpc_app = context;
  124. RpcSession* session = rpc_app->session;
  125. furi_assert(session);
  126. PB_CommandStatus status;
  127. if(rpc_app->app_callback) {
  128. const char* args = request->content.app_button_press_request.args;
  129. if(rpc_app->app_callback(RpcAppEventButtonPress, args, rpc_app->app_context)) {
  130. status = PB_CommandStatus_OK;
  131. furi_timer_start(rpc_app->timer, APP_BUTTON_TIMEOUT);
  132. } else {
  133. status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
  134. }
  135. } else {
  136. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  137. }
  138. rpc_send_and_release_empty(session, request->command_id, status);
  139. }
  140. static void rpc_system_app_button_release(const PB_Main* request, void* context) {
  141. furi_assert(request);
  142. furi_assert(request->which_content == PB_Main_app_button_release_request_tag);
  143. furi_assert(context);
  144. RpcAppSystem* rpc_app = context;
  145. RpcSession* session = rpc_app->session;
  146. furi_assert(session);
  147. PB_CommandStatus status;
  148. if(rpc_app->app_callback) {
  149. if(rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context)) {
  150. status = PB_CommandStatus_OK;
  151. furi_timer_stop(rpc_app->timer);
  152. } else {
  153. status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
  154. }
  155. } else {
  156. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  157. }
  158. rpc_send_and_release_empty(session, request->command_id, status);
  159. }
  160. void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) {
  161. furi_assert(rpc_app);
  162. rpc_app->app_callback = callback;
  163. rpc_app->app_context = ctx;
  164. }
  165. void* rpc_system_app_alloc(RpcSession* session) {
  166. furi_assert(session);
  167. RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem));
  168. rpc_app->session = session;
  169. rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app);
  170. RpcHandler rpc_handler = {
  171. .message_handler = NULL,
  172. .decode_submessage = NULL,
  173. .context = rpc_app,
  174. };
  175. rpc_handler.message_handler = rpc_system_app_start_process;
  176. rpc_add_handler(session, PB_Main_app_start_request_tag, &rpc_handler);
  177. rpc_handler.message_handler = rpc_system_app_lock_status_process;
  178. rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler);
  179. rpc_handler.message_handler = rpc_system_app_exit;
  180. rpc_add_handler(session, PB_Main_app_exit_request_tag, &rpc_handler);
  181. rpc_handler.message_handler = rpc_system_app_load_file;
  182. rpc_add_handler(session, PB_Main_app_load_file_request_tag, &rpc_handler);
  183. rpc_handler.message_handler = rpc_system_app_button_press;
  184. rpc_add_handler(session, PB_Main_app_button_press_request_tag, &rpc_handler);
  185. rpc_handler.message_handler = rpc_system_app_button_release;
  186. rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler);
  187. return rpc_app;
  188. }
  189. void rpc_system_app_free(void* context) {
  190. RpcAppSystem* rpc_app = context;
  191. RpcSession* session = rpc_app->session;
  192. furi_assert(session);
  193. furi_timer_free(rpc_app->timer);
  194. if(rpc_app->app_callback) {
  195. rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context);
  196. }
  197. free(rpc_app);
  198. }