rpc_app.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. struct RpcAppSystem {
  9. RpcSession* session;
  10. RpcAppSystemCallback app_callback;
  11. void* app_context;
  12. RpcAppSystemDataExchangeCallback data_exchange_callback;
  13. void* data_exchange_context;
  14. PB_Main* state_msg;
  15. PB_Main* error_msg;
  16. uint32_t last_id;
  17. char* last_data;
  18. };
  19. #define RPC_SYSTEM_APP_TEMP_ARGS_SIZE 16
  20. static void rpc_system_app_start_process(const PB_Main* request, void* context) {
  21. furi_assert(request);
  22. furi_assert(context);
  23. furi_assert(request->which_content == PB_Main_app_start_request_tag);
  24. RpcAppSystem* rpc_app = context;
  25. RpcSession* session = rpc_app->session;
  26. furi_assert(session);
  27. char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE];
  28. furi_assert(!rpc_app->last_id);
  29. furi_assert(!rpc_app->last_data);
  30. FURI_LOG_D(TAG, "StartProcess: id %ld", request->command_id);
  31. PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START;
  32. Loader* loader = furi_record_open(RECORD_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(app_args && strcmp(app_args, "RPC") == 0) {
  37. // If app is being started in RPC mode - pass RPC context via args string
  38. snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "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_crash("Programming Error");
  52. }
  53. } else {
  54. result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
  55. }
  56. furi_record_close(RECORD_LOADER);
  57. FURI_LOG_D(TAG, "StartProcess: response id %ld, result %d", request->command_id, result);
  58. rpc_send_and_release_empty(session, request->command_id, result);
  59. }
  60. static void rpc_system_app_lock_status_process(const PB_Main* request, void* context) {
  61. furi_assert(request);
  62. furi_assert(context);
  63. furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
  64. RpcAppSystem* rpc_app = context;
  65. RpcSession* session = rpc_app->session;
  66. furi_assert(session);
  67. FURI_LOG_D(TAG, "LockStatus");
  68. Loader* loader = furi_record_open(RECORD_LOADER);
  69. PB_Main response = {
  70. .has_next = false,
  71. .command_status = PB_CommandStatus_OK,
  72. .command_id = request->command_id,
  73. .which_content = PB_Main_app_lock_status_response_tag,
  74. };
  75. response.content.app_lock_status_response.locked = loader_is_locked(loader);
  76. furi_record_close(RECORD_LOADER);
  77. FURI_LOG_D(TAG, "LockStatus: response");
  78. rpc_send_and_release(session, &response);
  79. pb_release(&PB_Main_msg, &response);
  80. }
  81. static void rpc_system_app_exit_request(const PB_Main* request, void* context) {
  82. furi_assert(request);
  83. furi_assert(context);
  84. furi_assert(request->which_content == PB_Main_app_exit_request_tag);
  85. RpcAppSystem* rpc_app = context;
  86. RpcSession* session = rpc_app->session;
  87. furi_assert(session);
  88. PB_CommandStatus status;
  89. if(rpc_app->app_callback) {
  90. FURI_LOG_D(TAG, "ExitRequest: id %ld", request->command_id);
  91. furi_assert(!rpc_app->last_id);
  92. furi_assert(!rpc_app->last_data);
  93. rpc_app->last_id = request->command_id;
  94. rpc_app->app_callback(RpcAppEventAppExit, rpc_app->app_context);
  95. } else {
  96. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  97. FURI_LOG_E(
  98. TAG, "ExitRequest: APP_NOT_RUNNING, id %ld, status: %d", request->command_id, status);
  99. rpc_send_and_release_empty(session, request->command_id, status);
  100. }
  101. }
  102. static void rpc_system_app_load_file(const PB_Main* request, void* context) {
  103. furi_assert(request);
  104. furi_assert(context);
  105. furi_assert(request->which_content == PB_Main_app_load_file_request_tag);
  106. RpcAppSystem* rpc_app = context;
  107. RpcSession* session = rpc_app->session;
  108. furi_assert(session);
  109. PB_CommandStatus status;
  110. if(rpc_app->app_callback) {
  111. FURI_LOG_D(TAG, "LoadFile: id %ld", request->command_id);
  112. furi_assert(!rpc_app->last_id);
  113. furi_assert(!rpc_app->last_data);
  114. rpc_app->last_id = request->command_id;
  115. rpc_app->last_data = strdup(request->content.app_load_file_request.path);
  116. rpc_app->app_callback(RpcAppEventLoadFile, rpc_app->app_context);
  117. } else {
  118. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  119. FURI_LOG_E(
  120. TAG, "LoadFile: APP_NOT_RUNNING, id %ld, status: %d", request->command_id, status);
  121. rpc_send_and_release_empty(session, request->command_id, status);
  122. }
  123. }
  124. static void rpc_system_app_button_press(const PB_Main* request, void* context) {
  125. furi_assert(request);
  126. furi_assert(context);
  127. furi_assert(request->which_content == PB_Main_app_button_press_request_tag);
  128. RpcAppSystem* rpc_app = context;
  129. RpcSession* session = rpc_app->session;
  130. furi_assert(session);
  131. PB_CommandStatus status;
  132. if(rpc_app->app_callback) {
  133. FURI_LOG_D(TAG, "ButtonPress");
  134. furi_assert(!rpc_app->last_id);
  135. furi_assert(!rpc_app->last_data);
  136. rpc_app->last_id = request->command_id;
  137. rpc_app->last_data = strdup(request->content.app_button_press_request.args);
  138. rpc_app->app_callback(RpcAppEventButtonPress, rpc_app->app_context);
  139. } else {
  140. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  141. FURI_LOG_E(
  142. TAG, "ButtonPress: APP_NOT_RUNNING, id %ld, status: %d", request->command_id, status);
  143. rpc_send_and_release_empty(session, request->command_id, status);
  144. }
  145. }
  146. static void rpc_system_app_button_release(const PB_Main* request, void* context) {
  147. furi_assert(request);
  148. furi_assert(request->which_content == PB_Main_app_button_release_request_tag);
  149. furi_assert(context);
  150. RpcAppSystem* rpc_app = context;
  151. RpcSession* session = rpc_app->session;
  152. furi_assert(session);
  153. PB_CommandStatus status;
  154. if(rpc_app->app_callback) {
  155. FURI_LOG_D(TAG, "ButtonRelease");
  156. furi_assert(!rpc_app->last_id);
  157. furi_assert(!rpc_app->last_data);
  158. rpc_app->last_id = request->command_id;
  159. rpc_app->app_callback(RpcAppEventButtonRelease, rpc_app->app_context);
  160. } else {
  161. status = PB_CommandStatus_ERROR_APP_NOT_RUNNING;
  162. FURI_LOG_E(
  163. TAG, "ButtonRelease: APP_NOT_RUNNING, id %ld, status: %d", request->command_id, status);
  164. rpc_send_and_release_empty(session, request->command_id, status);
  165. }
  166. }
  167. static void rpc_system_app_get_error_process(const PB_Main* request, void* context) {
  168. furi_assert(request);
  169. furi_assert(request->which_content == PB_Main_app_get_error_request_tag);
  170. furi_assert(context);
  171. RpcAppSystem* rpc_app = context;
  172. RpcSession* session = rpc_app->session;
  173. furi_assert(session);
  174. rpc_app->error_msg->command_id = request->command_id;
  175. FURI_LOG_D(TAG, "GetError");
  176. rpc_send(session, rpc_app->error_msg);
  177. }
  178. static void rpc_system_app_data_exchange_process(const PB_Main* request, void* context) {
  179. furi_assert(request);
  180. furi_assert(request->which_content == PB_Main_app_data_exchange_request_tag);
  181. furi_assert(context);
  182. RpcAppSystem* rpc_app = context;
  183. RpcSession* session = rpc_app->session;
  184. furi_assert(session);
  185. PB_CommandStatus command_status;
  186. pb_bytes_array_t* data = request->content.app_data_exchange_request.data;
  187. if(rpc_app->data_exchange_callback) {
  188. uint8_t* data_bytes = NULL;
  189. size_t data_size = 0;
  190. if(data) {
  191. data_bytes = data->bytes;
  192. data_size = data->size;
  193. }
  194. rpc_app->data_exchange_callback(data_bytes, data_size, rpc_app->data_exchange_context);
  195. command_status = PB_CommandStatus_OK;
  196. } else {
  197. command_status = PB_CommandStatus_ERROR_APP_CMD_ERROR;
  198. }
  199. FURI_LOG_D(TAG, "DataExchange");
  200. rpc_send_and_release_empty(session, request->command_id, command_status);
  201. }
  202. void rpc_system_app_send_started(RpcAppSystem* rpc_app) {
  203. furi_assert(rpc_app);
  204. RpcSession* session = rpc_app->session;
  205. furi_assert(session);
  206. rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED;
  207. FURI_LOG_D(TAG, "SendStarted");
  208. rpc_send(session, rpc_app->state_msg);
  209. }
  210. void rpc_system_app_send_exited(RpcAppSystem* rpc_app) {
  211. furi_assert(rpc_app);
  212. RpcSession* session = rpc_app->session;
  213. furi_assert(session);
  214. rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED;
  215. FURI_LOG_D(TAG, "SendExit");
  216. rpc_send(session, rpc_app->state_msg);
  217. }
  218. const char* rpc_system_app_get_data(RpcAppSystem* rpc_app) {
  219. furi_assert(rpc_app);
  220. furi_assert(rpc_app->last_data);
  221. return rpc_app->last_data;
  222. }
  223. void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result) {
  224. furi_assert(rpc_app);
  225. RpcSession* session = rpc_app->session;
  226. furi_assert(session);
  227. furi_assert(rpc_app->last_id);
  228. PB_CommandStatus status = result ? PB_CommandStatus_OK : PB_CommandStatus_ERROR_APP_CMD_ERROR;
  229. uint32_t last_id = 0;
  230. switch(event) {
  231. case RpcAppEventAppExit:
  232. case RpcAppEventLoadFile:
  233. case RpcAppEventButtonPress:
  234. case RpcAppEventButtonRelease:
  235. last_id = rpc_app->last_id;
  236. rpc_app->last_id = 0;
  237. if(rpc_app->last_data) {
  238. free(rpc_app->last_data);
  239. rpc_app->last_data = NULL;
  240. }
  241. FURI_LOG_D(TAG, "AppConfirm: event %d last_id %ld status %d", event, last_id, status);
  242. rpc_send_and_release_empty(session, last_id, status);
  243. break;
  244. default:
  245. furi_crash("RPC App state programming Error");
  246. break;
  247. }
  248. }
  249. void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) {
  250. furi_assert(rpc_app);
  251. rpc_app->app_callback = callback;
  252. rpc_app->app_context = ctx;
  253. }
  254. void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code) {
  255. furi_assert(rpc_app);
  256. PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response;
  257. content->code = error_code;
  258. }
  259. void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text) {
  260. furi_assert(rpc_app);
  261. PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response;
  262. if(content->text) {
  263. free(content->text);
  264. }
  265. content->text = error_text ? strdup(error_text) : NULL;
  266. }
  267. void rpc_system_app_set_data_exchange_callback(
  268. RpcAppSystem* rpc_app,
  269. RpcAppSystemDataExchangeCallback callback,
  270. void* ctx) {
  271. furi_assert(rpc_app);
  272. rpc_app->data_exchange_callback = callback;
  273. rpc_app->data_exchange_context = ctx;
  274. }
  275. void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, size_t data_size) {
  276. furi_assert(rpc_app);
  277. RpcSession* session = rpc_app->session;
  278. furi_assert(session);
  279. PB_Main message = {
  280. .command_id = 0,
  281. .command_status = PB_CommandStatus_OK,
  282. .has_next = false,
  283. .which_content = PB_Main_app_data_exchange_request_tag,
  284. };
  285. PB_App_DataExchangeRequest* content = &message.content.app_data_exchange_request;
  286. if(data && data_size) {
  287. content->data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data_size));
  288. content->data->size = data_size;
  289. memcpy(content->data->bytes, data, data_size);
  290. } else {
  291. content->data = NULL;
  292. }
  293. rpc_send_and_release(session, &message);
  294. }
  295. void* rpc_system_app_alloc(RpcSession* session) {
  296. furi_assert(session);
  297. RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem));
  298. rpc_app->session = session;
  299. // App exit message
  300. rpc_app->state_msg = malloc(sizeof(PB_Main));
  301. rpc_app->state_msg->which_content = PB_Main_app_state_response_tag;
  302. rpc_app->state_msg->command_status = PB_CommandStatus_OK;
  303. // App error message
  304. rpc_app->error_msg = malloc(sizeof(PB_Main));
  305. rpc_app->error_msg->which_content = PB_Main_app_get_error_response_tag;
  306. rpc_app->error_msg->command_status = PB_CommandStatus_OK;
  307. rpc_app->error_msg->content.app_get_error_response.code = 0;
  308. rpc_app->error_msg->content.app_get_error_response.text = NULL;
  309. RpcHandler rpc_handler = {
  310. .message_handler = NULL,
  311. .decode_submessage = NULL,
  312. .context = rpc_app,
  313. };
  314. rpc_handler.message_handler = rpc_system_app_start_process;
  315. rpc_add_handler(session, PB_Main_app_start_request_tag, &rpc_handler);
  316. rpc_handler.message_handler = rpc_system_app_lock_status_process;
  317. rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler);
  318. rpc_handler.message_handler = rpc_system_app_exit_request;
  319. rpc_add_handler(session, PB_Main_app_exit_request_tag, &rpc_handler);
  320. rpc_handler.message_handler = rpc_system_app_load_file;
  321. rpc_add_handler(session, PB_Main_app_load_file_request_tag, &rpc_handler);
  322. rpc_handler.message_handler = rpc_system_app_button_press;
  323. rpc_add_handler(session, PB_Main_app_button_press_request_tag, &rpc_handler);
  324. rpc_handler.message_handler = rpc_system_app_button_release;
  325. rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler);
  326. rpc_handler.message_handler = rpc_system_app_get_error_process;
  327. rpc_add_handler(session, PB_Main_app_get_error_request_tag, &rpc_handler);
  328. rpc_handler.message_handler = rpc_system_app_data_exchange_process;
  329. rpc_add_handler(session, PB_Main_app_data_exchange_request_tag, &rpc_handler);
  330. return rpc_app;
  331. }
  332. void rpc_system_app_free(void* context) {
  333. RpcAppSystem* rpc_app = context;
  334. furi_assert(rpc_app);
  335. RpcSession* session = rpc_app->session;
  336. furi_assert(session);
  337. if(rpc_app->app_callback) {
  338. rpc_app->app_callback(RpcAppEventSessionClose, rpc_app->app_context);
  339. }
  340. while(rpc_app->app_callback) {
  341. furi_delay_tick(1);
  342. }
  343. furi_assert(!rpc_app->data_exchange_callback);
  344. if(rpc_app->last_data) free(rpc_app->last_data);
  345. pb_release(&PB_Main_msg, rpc_app->error_msg);
  346. free(rpc_app->error_msg);
  347. free(rpc_app->state_msg);
  348. free(rpc_app);
  349. }