[FL-1946] RPC App launch (#758)

* RPC: Add App start, lock status
 - Add RPC commands Application start, lock status acquiring.
 - Write tests for RPC App system.
 - Replace Unit Tests application with CLI command. This is for CI needs and for tests that run application.
* Fix NDEBUG build
* Update PB submodule
* Fix RPC print (ENABLE DEBUG PRINT!)
* snprintf -> string_t
* Fix Hard Fault (early mutex free)
* printf -> string_t, format, enable tests
* Update submodule: protobuf
* Applications: rollback unit test naming scheme.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Albert Kharisov
2021-10-13 19:39:37 +04:00
committed by GitHub
parent a643bd14be
commit 1db29eaea8
16 changed files with 494 additions and 96 deletions

View File

@@ -4,6 +4,7 @@
#include "furi-hal-delay.h"
#include "furi/check.h"
#include "furi/log.h"
#include <m-string.h>
#include "pb.h"
#include "pb_decode.h"
#include "pb_encode.h"
@@ -42,6 +43,10 @@ static RpcSystemCallbacks rpc_systems[] = {
.alloc = rpc_system_storage_alloc,
.free = rpc_system_storage_free,
},
{
.alloc = rpc_system_app_alloc,
.free = NULL,
},
};
struct RpcSession {
@@ -65,31 +70,28 @@ struct Rpc {
static bool content_callback(pb_istream_t* stream, const pb_field_t* field, void** arg);
static size_t rpc_sprint_msg_file(
char* str,
size_t str_size,
static size_t rpc_sprintf_msg_file(
string_t str,
const char* prefix,
const PB_Storage_File* msg_file,
size_t msg_files_size) {
size_t cnt = 0;
for(int i = 0; i < msg_files_size; ++i, ++msg_file) {
cnt += snprintf(
str + cnt,
str_size - cnt,
string_cat_printf(
str,
"%s[%c] size: %5ld",
prefix,
msg_file->type == PB_Storage_File_FileType_DIR ? 'd' : 'f',
msg_file->size);
if(msg_file->name) {
cnt += snprintf(str + cnt, str_size - cnt, " \'%s\'", msg_file->name);
string_cat_printf(str, " \'%s\'", msg_file->name);
}
if(msg_file->data && msg_file->data->size) {
cnt += snprintf(
str + cnt,
str_size - cnt,
string_cat_printf(
str,
" (%d):\'%.*s%s\'",
msg_file->data->size,
MIN(msg_file->data->size, 30),
@@ -97,23 +99,18 @@ static size_t rpc_sprint_msg_file(
msg_file->data->size > 30 ? "..." : "");
}
cnt += snprintf(str + cnt, str_size - cnt, "\r\n");
string_cat_printf(str, "\r\n");
}
return cnt;
}
#define ADD_STR(s, c, ...) snprintf(s + c, sizeof(s) - c, ##__VA_ARGS__);
#define ADD_STR_ELEMENT(s, c, ...) rpc_sprint_msg_file(s + c, sizeof(s) - c, ##__VA_ARGS__);
void rpc_print_message(const PB_Main* message) {
char str[500];
size_t cnt = 0;
string_t str;
string_init(str);
cnt += snprintf(
str + cnt,
sizeof(str) - cnt,
string_cat_printf(
str,
"PB_Main: {\r\n\tresult: %d cmd_id: %ld (%s)\r\n",
message->command_status,
message->command_id,
@@ -121,88 +118,112 @@ void rpc_print_message(const PB_Main* message) {
switch(message->which_content) {
default:
/* not implemented yet */
cnt += ADD_STR(str, cnt, "\tNOT_IMPLEMENTED (%d) {\r\n", message->which_content);
string_cat_printf(str, "\tNOT_IMPLEMENTED (%d) {\r\n", message->which_content);
break;
case PB_Main_app_start_tag: {
string_cat_printf(str, "\tapp_start {\r\n");
const char* name = message->content.app_start.name;
const char* args = message->content.app_start.args;
if(name) {
string_cat_printf(str, "\t\tname: %s\r\n", name);
}
if(args) {
string_cat_printf(str, "\t\targs: %s\r\n", args);
}
break;
}
case PB_Main_app_lock_status_request_tag: {
string_cat_printf(str, "\tapp_lock_status_request {\r\n");
break;
}
case PB_Main_app_lock_status_response_tag: {
string_cat_printf(str, "\tapp_lock_status_response {\r\n");
bool lock_status = message->content.app_lock_status_response.locked;
string_cat_printf(str, "\t\tlocked: %s\r\n", lock_status ? "true" : "false");
break;
}
case PB_Main_storage_md5sum_request_tag: {
cnt += ADD_STR(str, cnt, "\tmd5sum_request {\r\n");
string_cat_printf(str, "\tmd5sum_request {\r\n");
const char* path = message->content.storage_md5sum_request.path;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tpath: %s\r\n", path);
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_storage_md5sum_response_tag: {
cnt += ADD_STR(str, cnt, "\tmd5sum_response {\r\n");
string_cat_printf(str, "\tmd5sum_response {\r\n");
const char* path = message->content.storage_md5sum_response.md5sum;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tmd5sum: %s\r\n", path);
string_cat_printf(str, "\t\tmd5sum: %s\r\n", path);
}
break;
}
case PB_Main_ping_request_tag:
cnt += ADD_STR(str, cnt, "\tping_request {\r\n");
string_cat_printf(str, "\tping_request {\r\n");
break;
case PB_Main_ping_response_tag:
cnt += ADD_STR(str, cnt, "\tping_response {\r\n");
string_cat_printf(str, "\tping_response {\r\n");
break;
case PB_Main_storage_mkdir_request_tag:
cnt += ADD_STR(str, cnt, "\tmkdir {\r\n");
string_cat_printf(str, "\tmkdir {\r\n");
break;
case PB_Main_storage_delete_request_tag: {
cnt += ADD_STR(str, cnt, "\tdelete {\r\n");
string_cat_printf(str, "\tdelete {\r\n");
const char* path = message->content.storage_delete_request.path;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tpath: %s\r\n", path);
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_empty_tag:
cnt += ADD_STR(str, cnt, "\tempty {\r\n");
string_cat_printf(str, "\tempty {\r\n");
break;
case PB_Main_storage_list_request_tag: {
cnt += ADD_STR(str, cnt, "\tlist_request {\r\n");
string_cat_printf(str, "\tlist_request {\r\n");
const char* path = message->content.storage_list_request.path;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tpath: %s\r\n", path);
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_storage_read_request_tag: {
cnt += ADD_STR(str, cnt, "\tread_request {\r\n");
string_cat_printf(str, "\tread_request {\r\n");
const char* path = message->content.storage_read_request.path;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tpath: %s\r\n", path);
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_storage_write_request_tag: {
cnt += ADD_STR(str, cnt, "\twrite_request {\r\n");
string_cat_printf(str, "\twrite_request {\r\n");
const char* path = message->content.storage_write_request.path;
if(path) {
cnt += ADD_STR(str, cnt, "\t\tpath: %s\r\n", path);
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
if(message->content.storage_write_request.has_file) {
const PB_Storage_File* msg_file = &message->content.storage_write_request.file;
cnt += ADD_STR_ELEMENT(str, cnt, "\t\t\t", msg_file, 1);
rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1);
}
break;
}
case PB_Main_storage_read_response_tag:
cnt += ADD_STR(str, cnt, "\tread_response {\r\n");
string_cat_printf(str, "\tread_response {\r\n");
if(message->content.storage_read_response.has_file) {
const PB_Storage_File* msg_file = &message->content.storage_read_response.file;
cnt += ADD_STR_ELEMENT(str, cnt, "\t\t\t", msg_file, 1);
rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1);
}
break;
case PB_Main_storage_list_response_tag: {
const PB_Storage_File* msg_file = message->content.storage_list_response.file;
size_t msg_file_count = message->content.storage_list_response.file_count;
cnt += ADD_STR(str, cnt, "\tlist_response {\r\n");
cnt += ADD_STR_ELEMENT(str, cnt, "\t\t", msg_file, msg_file_count);
string_cat_printf(str, "\tlist_response {\r\n");
rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count);
}
}
cnt += ADD_STR(str, cnt, "\t}\r\n}\r\n");
printf("%s", str);
string_cat_printf(str, "\t}\r\n}\r\n");
printf("%s", string_get_cstr(str));
string_clear(str);
}
static Rpc* rpc_alloc(void) {
@@ -253,7 +274,6 @@ void rpc_close_session(RpcSession* session) {
furi_assert(session->rpc);
furi_assert(session->rpc->busy);
osMutexDelete(session->send_bytes_mutex);
rpc_set_send_bytes_callback(session, NULL, NULL);
osEventFlagsSet(session->rpc->events, RPC_EVENT_DISCONNECT);
}
@@ -328,22 +348,31 @@ void rpc_encode_and_send(Rpc* rpc, PB_Main* main_message) {
pb_encode_ex(&ostream, &PB_Main_msg, main_message, PB_ENCODE_DELIMITED);
{
osMutexAcquire(session->send_bytes_mutex, osWaitForever);
#if DEBUG_PRINT
printf("\r\nREPONSE DEC(%d): {", ostream.bytes_written);
for(int i = 0; i < ostream.bytes_written; ++i) {
printf("%d, ", buffer[i]);
}
printf("}\r\n");
string_t str;
string_init(str);
string_reserve(str, 100 + ostream.bytes_written * 5);
printf("REPONSE HEX(%d): {", ostream.bytes_written);
string_cat_printf(str, "\r\nREPONSE DEC(%d): {", ostream.bytes_written);
for(int i = 0; i < ostream.bytes_written; ++i) {
printf("%02X", buffer[i]);
string_cat_printf(str, "%d, ", buffer[i]);
}
printf("}\r\n\r\n");
string_cat_printf(str, "}\r\n");
printf("%s", string_get_cstr(str));
string_clean(str);
string_reserve(str, 100 + ostream.bytes_written * 3);
string_cat_printf(str, "REPONSE HEX(%d): {", ostream.bytes_written);
for(int i = 0; i < ostream.bytes_written; ++i) {
string_cat_printf(str, "%02X", buffer[i]);
}
string_cat_printf(str, "}\r\n\r\n");
printf("%s", string_get_cstr(str));
#endif // DEBUG_PRINT
osMutexAcquire(session->send_bytes_mutex, osWaitForever);
if(session->send_bytes_callback) {
session->send_bytes_callback(
session->send_bytes_context, buffer, ostream.bytes_written);
@@ -408,6 +437,7 @@ int32_t rpc_srv(void* p) {
}
}
free(session->system_contexts);
osMutexDelete(session->send_bytes_mutex);
RpcHandlerDict_clean(rpc->handlers);
rpc->busy = false;
} else {

View File

@@ -0,0 +1,78 @@
#include "flipper.pb.h"
#include "furi/record.h"
#include "status.pb.h"
#include "rpc_i.h"
#include <furi.h>
#include <loader/loader.h>
void rpc_system_app_start_process(const PB_Main* request, void* context) {
Rpc* rpc = context;
furi_assert(rpc);
furi_assert(request);
furi_assert(request->which_content == PB_Main_app_start_tag);
PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START;
Loader* loader = furi_record_open("loader");
const char* app_name = request->content.app_start.name;
if(app_name) {
const char* app_args = request->content.app_start.args;
LoaderStatus status = loader_start(loader, app_name, app_args);
if(status == LoaderStatusErrorAppStarted) {
result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED;
} else if(status == LoaderStatusErrorInternal) {
result = PB_CommandStatus_ERROR_APP_CANT_START;
} else if(status == LoaderStatusErrorUnknownApp) {
result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
} else if(status == LoaderStatusOk) {
result = PB_CommandStatus_OK;
} else {
furi_assert(0);
}
} else {
result = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
}
furi_record_close("loader");
rpc_encode_and_send_empty(rpc, request->command_id, result);
}
void rpc_system_app_lock_status_process(const PB_Main* request, void* context) {
Rpc* rpc = context;
furi_assert(rpc);
furi_assert(request);
furi_assert(request->which_content == PB_Main_app_lock_status_request_tag);
Loader* loader = furi_record_open("loader");
PB_Main response = {
.has_next = false,
.command_status = PB_CommandStatus_OK,
.command_id = request->command_id,
.which_content = PB_Main_app_lock_status_response_tag,
};
response.content.app_lock_status_response.locked = loader_is_locked(loader);
furi_record_close("loader");
rpc_encode_and_send(rpc, &response);
}
void* rpc_system_app_alloc(Rpc* rpc) {
furi_assert(rpc);
RpcHandler rpc_handler = {
.message_handler = NULL,
.decode_submessage = NULL,
.context = rpc,
};
rpc_handler.message_handler = rpc_system_app_start_process;
rpc_add_handler(rpc, PB_Main_app_start_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_app_lock_status_process;
rpc_add_handler(rpc, PB_Main_app_lock_status_request_tag, &rpc_handler);
return NULL;
}

View File

@@ -22,4 +22,6 @@ void rpc_add_handler(Rpc* rpc, pb_size_t message_tag, RpcHandler* handler);
void* rpc_system_status_alloc(Rpc* rpc);
void* rpc_system_storage_alloc(Rpc* rpc);
void rpc_system_storage_free(void* ctx);
void* rpc_system_app_alloc(Rpc* rpc);
void rpc_print_message(const PB_Main* message);

View File

@@ -340,6 +340,7 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
char* md5sum = response.content.storage_md5sum_response.md5sum;
size_t md5sum_size = sizeof(response.content.storage_md5sum_response.md5sum);
(void)md5sum_size;
furi_assert(hash_size <= ((md5sum_size - 1) / 2));
for(uint8_t i = 0; i < hash_size; i++) {
md5sum += sprintf(md5sum, "%02x", hash[i]);