[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:
		
							parent
							
								
									a643bd14be
								
							
						
					
					
						commit
						1db29eaea8
					
				| @ -20,7 +20,7 @@ extern int32_t desktop_srv(void* p); | ||||
| extern int32_t accessor_app(void* p); | ||||
| extern int32_t archive_app(void* p); | ||||
| extern int32_t blink_test_app(void* p); | ||||
| extern int32_t flipper_test_app(void* p); | ||||
| extern int32_t delay_test_app(void* p); | ||||
| extern int32_t gpio_app(void* p); | ||||
| extern int32_t ibutton_app(void* p); | ||||
| extern int32_t irda_app(void* p); | ||||
| @ -49,6 +49,7 @@ extern void nfc_cli_init(); | ||||
| extern void storage_cli_init(); | ||||
| extern void subghz_cli_init(); | ||||
| extern void power_cli_init(); | ||||
| extern void unit_tests_cli_init(); | ||||
| 
 | ||||
| // Settings
 | ||||
| extern int32_t notification_settings_app(void* p); | ||||
| @ -183,6 +184,10 @@ const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = { | ||||
| #ifdef SRV_STORAGE | ||||
|     storage_cli_init, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_UNIT_TESTS | ||||
|     unit_tests_cli_init, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| const size_t FLIPPER_ON_SYSTEM_START_COUNT = | ||||
| @ -220,10 +225,6 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | ||||
|     {.app = usb_test_app, .name = "USB Test", .stack_size = 1024, .icon = &A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_UNIT_TESTS | ||||
|     {.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024 * 8, .icon = &A_Plugins_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_IRDA_MONITOR | ||||
|     {.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = &A_Plugins_14}, | ||||
| #endif | ||||
| @ -239,6 +240,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | ||||
| #ifdef SRV_BT | ||||
|     {.app = bt_debug_app, .name = "Bluetooth Debug", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_UNIT_TESTS | ||||
|     {.app = delay_test_app, .name = "Delay Test App", .stack_size = 1024, .icon = &A_Plugins_14}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | ||||
|  | ||||
| @ -42,7 +42,6 @@ APP_BLINK	= 1 | ||||
| APP_IRDA_MONITOR = 1 | ||||
| APP_KEYPAD_TEST = 1 | ||||
| APP_SD_TEST	= 1 | ||||
| APP_UNIT_TESTS = 0 | ||||
| APP_VIBRO_DEMO = 1 | ||||
| APP_USB_TEST = 1 | ||||
| endif | ||||
| @ -60,7 +59,7 @@ SRV_GUI		= 1 | ||||
| endif | ||||
| 
 | ||||
| 
 | ||||
| APP_UNIT_TESTS	?= 0 | ||||
| APP_UNIT_TESTS ?= 0 | ||||
| ifeq ($(APP_UNIT_TESTS), 1) | ||||
| CFLAGS		+= -DAPP_UNIT_TESTS | ||||
| endif | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| #include "loader/loader.h" | ||||
| #include "loader_i.h" | ||||
| 
 | ||||
| #define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) | ||||
| @ -56,7 +57,7 @@ static void loader_cli_callback(Cli* cli, string_t args, void* _ctx) { | ||||
|     furi_thread_start(loader_instance->thread); | ||||
| } | ||||
| 
 | ||||
| bool loader_start(Loader* instance, const char* name, const char* args) { | ||||
| LoaderStatus loader_start(Loader* instance, const char* name, const char* args) { | ||||
|     furi_assert(name); | ||||
| 
 | ||||
|     const FlipperApplication* flipper_app = NULL; | ||||
| @ -79,14 +80,15 @@ bool loader_start(Loader* instance, const char* name, const char* args) { | ||||
| 
 | ||||
|     if(!flipper_app) { | ||||
|         FURI_LOG_E(LOADER_LOG_TAG, "Can't find application with name %s", name); | ||||
|         return false; | ||||
|         return LoaderStatusErrorUnknownApp; | ||||
|     } | ||||
| 
 | ||||
|     loader_lock(instance); | ||||
|     bool locked = loader_lock(instance); | ||||
| 
 | ||||
|     if(furi_thread_get_state(instance->thread) != FuriThreadStateStopped) { | ||||
|     if(!locked || (furi_thread_get_state(instance->thread) != FuriThreadStateStopped)) { | ||||
|         FURI_LOG_E(LOADER_LOG_TAG, "Can't start app. %s is running", instance->current_app->name); | ||||
|         return false; | ||||
|         /* no need to call loader_unlock() - it is called as soon as application stops */ | ||||
|         return LoaderStatusErrorAppStarted; | ||||
|     } | ||||
| 
 | ||||
|     instance->current_app = flipper_app; | ||||
| @ -106,7 +108,8 @@ bool loader_start(Loader* instance, const char* name, const char* args) { | ||||
|     furi_thread_set_context(instance->thread, thread_args); | ||||
|     furi_thread_set_callback(instance->thread, flipper_app->app); | ||||
| 
 | ||||
|     return furi_thread_start(instance->thread); | ||||
|     bool thread_started = furi_thread_start(instance->thread); | ||||
|     return thread_started ? LoaderStatusOk : LoaderStatusErrorInternal; | ||||
| } | ||||
| 
 | ||||
| bool loader_lock(Loader* instance) { | ||||
| @ -127,6 +130,10 @@ void loader_unlock(Loader* instance) { | ||||
|     furi_check(osMutexRelease(instance->mutex) == osOK); | ||||
| } | ||||
| 
 | ||||
| bool loader_is_locked(Loader* instance) { | ||||
|     return (instance->lock_semaphore > 0); | ||||
| } | ||||
| 
 | ||||
| static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|  | ||||
| @ -4,12 +4,19 @@ | ||||
| 
 | ||||
| typedef struct Loader Loader; | ||||
| 
 | ||||
| typedef enum { | ||||
|     LoaderStatusOk, | ||||
|     LoaderStatusErrorAppStarted, | ||||
|     LoaderStatusErrorUnknownApp, | ||||
|     LoaderStatusErrorInternal, | ||||
| } LoaderStatus; | ||||
| 
 | ||||
| /** Start application
 | ||||
|  * @param name - application name | ||||
|  * @param args - application arguments | ||||
|  * @retval true on success | ||||
|  */ | ||||
| bool loader_start(Loader* instance, const char* name, const char* args); | ||||
| LoaderStatus loader_start(Loader* instance, const char* name, const char* args); | ||||
| 
 | ||||
| /** Lock application start
 | ||||
|  * @retval true on success | ||||
| @ -19,5 +26,8 @@ bool loader_lock(Loader* instance); | ||||
| /** Unlock application start */ | ||||
| void loader_unlock(Loader* instance); | ||||
| 
 | ||||
| /** Get loader lock status */ | ||||
| bool loader_is_locked(Loader* instance); | ||||
| 
 | ||||
| /** Show primary loader */ | ||||
| void loader_show_menu(); | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
							
								
								
									
										78
									
								
								applications/rpc/rpc_app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								applications/rpc/rpc_app.c
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
| @ -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); | ||||
|  | ||||
| @ -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]); | ||||
|  | ||||
| @ -41,7 +41,7 @@ static uint32_t subghz_frequency_analyzer_worker_expRunningAverageAdaptive( | ||||
| static int32_t subghz_frequency_analyzer_worker_thread(void* context) { | ||||
|     SubGhzFrequencyAnalyzerWorker* instance = context; | ||||
| 
 | ||||
|     FrequencyRSSI frequency_rssi; | ||||
|     FrequencyRSSI frequency_rssi = {.frequency = 0, .rssi = 0}; | ||||
|     float rssi; | ||||
|     uint32_t frequency; | ||||
|     uint32_t frequency_start; | ||||
|  | ||||
| @ -14,6 +14,8 @@ | ||||
| #include <pb_encode.h> | ||||
| #include <m-list.h> | ||||
| #include <lib/toolbox/md5.h> | ||||
| #include <cli/cli.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| LIST_DEF(MsgList, PB_Main, M_POD_OPLIST) | ||||
| #define M_OPL_MsgList_t() LIST_OPLIST(MsgList) | ||||
| @ -108,6 +110,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) { | ||||
|         free(name); | ||||
|     } else { | ||||
|         FS_Error error = storage_common_mkdir(fs_api, clean_dir); | ||||
|         (void)error; | ||||
|         furi_assert(error == FSE_OK); | ||||
|     } | ||||
| 
 | ||||
| @ -172,6 +175,7 @@ static void output_bytes_callback(void* ctx, uint8_t* got_bytes, size_t got_size | ||||
|     StreamBufferHandle_t stream_buffer = ctx; | ||||
| 
 | ||||
|     size_t bytes_sent = xStreamBufferSend(stream_buffer, got_bytes, got_size, osWaitForever); | ||||
|     (void)bytes_sent; | ||||
|     furi_assert(bytes_sent == got_size); | ||||
| } | ||||
| 
 | ||||
| @ -346,6 +350,12 @@ static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) { | ||||
|         /* rpc doesn't send it */ | ||||
|         mu_check(0); | ||||
|         break; | ||||
|     case PB_Main_app_lock_status_response_tag: { | ||||
|         bool result_locked = result->content.app_lock_status_response.locked; | ||||
|         bool expected_locked = expected->content.app_lock_status_response.locked; | ||||
|         mu_check(result_locked == expected_locked); | ||||
|         break; | ||||
|     } | ||||
|     case PB_Main_storage_read_response_tag: { | ||||
|         bool result_has_msg_file = result->content.storage_read_response.has_file; | ||||
|         bool expected_has_msg_file = expected->content.storage_read_response.has_file; | ||||
| @ -588,6 +598,7 @@ static void test_storage_read_run(const char* path, uint32_t command_id) { | ||||
| static void test_create_dir(const char* path) { | ||||
|     Storage* fs_api = furi_record_open("storage"); | ||||
|     FS_Error error = storage_common_mkdir(fs_api, path); | ||||
|     (void)error; | ||||
|     furi_assert((error == FSE_OK) || (error == FSE_EXIST)); | ||||
|     furi_record_close("storage"); | ||||
| } | ||||
| @ -717,7 +728,7 @@ MU_TEST(test_storage_write) { | ||||
|         ++command_id, | ||||
|         PB_CommandStatus_ERROR_STORAGE_NOT_EXIST); | ||||
|     test_storage_write_run(TEST_DIR "test2.txt", 1, 50, ++command_id, PB_CommandStatus_OK); | ||||
|     test_storage_write_run(TEST_DIR "test2.txt", 4096, 1, ++command_id, PB_CommandStatus_OK); | ||||
|     test_storage_write_run(TEST_DIR "test2.txt", 512, 3, ++command_id, PB_CommandStatus_OK); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(test_storage_interrupt_continuous_same_system) { | ||||
| @ -866,6 +877,7 @@ MU_TEST(test_storage_mkdir) { | ||||
| 
 | ||||
|     Storage* fs_api = furi_record_open("storage"); | ||||
|     FS_Error error = storage_common_remove(fs_api, TEST_DIR "dir1"); | ||||
|     (void)error; | ||||
|     furi_assert(error == FSE_OK); | ||||
|     furi_record_close("storage"); | ||||
| 
 | ||||
| @ -1018,10 +1030,134 @@ MU_TEST_SUITE(test_rpc_storage) { | ||||
|     MU_RUN_TEST(test_storage_interrupt_continuous_another_system); | ||||
| } | ||||
| 
 | ||||
| static void test_app_create_request( | ||||
|     PB_Main* request, | ||||
|     const char* app_name, | ||||
|     const char* app_args, | ||||
|     uint32_t command_id) { | ||||
|     request->command_id = command_id; | ||||
|     request->command_status = PB_CommandStatus_OK; | ||||
|     request->cb_content.funcs.encode = NULL; | ||||
|     request->which_content = PB_Main_app_start_tag; | ||||
|     request->has_next = false; | ||||
| 
 | ||||
|     if(app_name) { | ||||
|         char* msg_app_name = furi_alloc(strlen(app_name) + 1); | ||||
|         strcpy(msg_app_name, app_name); | ||||
|         request->content.app_start.name = msg_app_name; | ||||
|     } else { | ||||
|         request->content.app_start.name = NULL; | ||||
|     } | ||||
| 
 | ||||
|     if(app_args) { | ||||
|         char* msg_app_args = furi_alloc(strlen(app_args) + 1); | ||||
|         strcpy(msg_app_args, app_args); | ||||
|         request->content.app_start.args = msg_app_args; | ||||
|     } else { | ||||
|         request->content.app_start.args = NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void test_app_start_run( | ||||
|     const char* app_name, | ||||
|     const char* app_args, | ||||
|     PB_CommandStatus status, | ||||
|     uint32_t command_id) { | ||||
|     PB_Main request; | ||||
|     MsgList_t expected_msg_list; | ||||
|     MsgList_init(expected_msg_list); | ||||
| 
 | ||||
|     test_app_create_request(&request, app_name, app_args, command_id); | ||||
|     test_rpc_add_empty_to_list(expected_msg_list, status, command_id); | ||||
| 
 | ||||
|     test_rpc_encode_and_feed_one(&request); | ||||
|     test_rpc_decode_and_compare(expected_msg_list); | ||||
| 
 | ||||
|     pb_release(&PB_Main_msg, &request); | ||||
|     test_rpc_free_msg_list(expected_msg_list); | ||||
| } | ||||
| 
 | ||||
| static void test_app_get_status_lock_run(bool locked_expected, uint32_t command_id) { | ||||
|     PB_Main request = { | ||||
|         .command_id = command_id, | ||||
|         .command_status = PB_CommandStatus_OK, | ||||
|         .which_content = PB_Main_app_lock_status_request_tag, | ||||
|         .has_next = false, | ||||
|     }; | ||||
| 
 | ||||
|     MsgList_t expected_msg_list; | ||||
|     MsgList_init(expected_msg_list); | ||||
|     PB_Main* response = MsgList_push_new(expected_msg_list); | ||||
|     response->command_id = command_id; | ||||
|     response->command_status = PB_CommandStatus_OK; | ||||
|     response->which_content = PB_Main_app_lock_status_response_tag; | ||||
|     response->has_next = false; | ||||
|     response->content.app_lock_status_response.locked = locked_expected; | ||||
| 
 | ||||
|     test_rpc_encode_and_feed_one(&request); | ||||
|     test_rpc_decode_and_compare(expected_msg_list); | ||||
| 
 | ||||
|     pb_release(&PB_Main_msg, &request); | ||||
|     test_rpc_free_msg_list(expected_msg_list); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(test_app_start_and_lock_status) { | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
|     test_app_start_run(NULL, "/ext/file", PB_CommandStatus_ERROR_INVALID_PARAMETERS, ++command_id); | ||||
|     test_app_start_run(NULL, NULL, PB_CommandStatus_ERROR_INVALID_PARAMETERS, ++command_id); | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
|     test_app_start_run( | ||||
|         "skynet_destroy_world_app", NULL, PB_CommandStatus_ERROR_INVALID_PARAMETERS, ++command_id); | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
| 
 | ||||
|     test_app_start_run("Delay Test App", "0", PB_CommandStatus_OK, ++command_id); | ||||
|     delay(100); | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
| 
 | ||||
|     test_app_start_run("Delay Test App", "200", PB_CommandStatus_OK, ++command_id); | ||||
|     test_app_get_status_lock_run(true, ++command_id); | ||||
|     delay(100); | ||||
|     test_app_get_status_lock_run(true, ++command_id); | ||||
|     test_app_start_run( | ||||
|         "Delay Test App", "0", PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED, ++command_id); | ||||
|     delay(200); | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
| 
 | ||||
|     test_app_start_run("Delay Test App", "500", PB_CommandStatus_OK, ++command_id); | ||||
|     delay(100); | ||||
|     test_app_get_status_lock_run(true, ++command_id); | ||||
|     test_app_start_run("Infrared", "0", PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED, ++command_id); | ||||
|     delay(100); | ||||
|     test_app_get_status_lock_run(true, ++command_id); | ||||
|     test_app_start_run( | ||||
|         "2_girls_1_app", "0", PB_CommandStatus_ERROR_INVALID_PARAMETERS, ++command_id); | ||||
|     delay(100); | ||||
|     test_app_get_status_lock_run(true, ++command_id); | ||||
|     delay(500); | ||||
|     test_app_get_status_lock_run(false, ++command_id); | ||||
| } | ||||
| 
 | ||||
| MU_TEST_SUITE(test_rpc_app) { | ||||
|     MU_SUITE_CONFIGURE(&test_rpc_storage_setup, &test_rpc_storage_teardown); | ||||
| 
 | ||||
|     MU_RUN_TEST(test_app_start_and_lock_status); | ||||
| } | ||||
| 
 | ||||
| int run_minunit_test_rpc() { | ||||
|     MU_RUN_SUITE(test_rpc_storage); | ||||
|     MU_RUN_SUITE(test_rpc_status); | ||||
|     MU_RUN_SUITE(test_rpc_app); | ||||
|     MU_REPORT(); | ||||
| 
 | ||||
|     return MU_EXIT_CODE; | ||||
| } | ||||
| 
 | ||||
| int32_t delay_test_app(void* p) { | ||||
|     int timeout = atoi((const char*)p); | ||||
| 
 | ||||
|     if(timeout > 0) { | ||||
|         delay(timeout); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @ -1,33 +1,51 @@ | ||||
| #include "m-string.h" | ||||
| #include <stdio.h> | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| #include "minunit_vars.h" | ||||
| #include <notification/notification-messages.h> | ||||
| #include <cli/cli.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| int run_minunit(); | ||||
| int run_minunit_test_irda_decoder_encoder(); | ||||
| int run_minunit_test_rpc(); | ||||
| 
 | ||||
| int32_t flipper_test_app(void* p) { | ||||
| void unit_tests_cli(Cli* cli, string_t args, void* context) { | ||||
|     uint32_t test_result = 0; | ||||
|     minunit_run = 0; | ||||
|     minunit_assert = 0; | ||||
|     minunit_fail = 0; | ||||
|     minunit_status = 0; | ||||
| 
 | ||||
|     Loader* loader = furi_record_open("loader"); | ||||
|     furi_record_close("loader"); | ||||
| 
 | ||||
|     NotificationApp* notification = furi_record_open("notification"); | ||||
| 
 | ||||
|     notification_message_block(notification, &sequence_set_only_blue_255); | ||||
| 
 | ||||
|     //    test_result |= run_minunit();     // disabled as it fails randomly
 | ||||
|     test_result |= run_minunit_test_irda_decoder_encoder(); | ||||
|     test_result |= run_minunit_test_rpc(); | ||||
| 
 | ||||
|     if(test_result == 0) { | ||||
|         // test passed
 | ||||
|         notification_message(notification, &sequence_success); | ||||
|     } else { | ||||
|         // test failed
 | ||||
|         notification_message(notification, &sequence_error); | ||||
|     } | ||||
| 
 | ||||
|     furi_record_close("notification"); | ||||
| 
 | ||||
|     return 0; | ||||
|     if(loader_is_locked(loader)) { | ||||
|         FURI_LOG_E("UNIT_TESTS", "RPC: stop all applications to run tests"); | ||||
|         notification_message(notification, &sequence_blink_magenta_100); | ||||
|     } else { | ||||
|         notification_message_block(notification, &sequence_set_only_blue_255); | ||||
| 
 | ||||
|         test_result |= run_minunit(); | ||||
|         test_result |= run_minunit_test_irda_decoder_encoder(); | ||||
|         test_result |= run_minunit_test_rpc(); | ||||
| 
 | ||||
|         if(test_result == 0) { | ||||
|             notification_message(notification, &sequence_success); | ||||
|             FURI_LOG_I("UNIT_TESTS", "PASSED"); | ||||
|         } else { | ||||
|             notification_message(notification, &sequence_error); | ||||
|             FURI_LOG_E("UNIT_TESTS", "FAILED"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void unit_tests_cli_init() { | ||||
|     Cli* cli = furi_record_open("cli"); | ||||
|     cli_add_command(cli, "unit_tests", CliCommandFlagParallelSafe, unit_tests_cli, NULL); | ||||
|     furi_record_close("cli"); | ||||
| } | ||||
|  | ||||
							
								
								
									
										18
									
								
								assets/compiled/application.pb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								assets/compiled/application.pb.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| /* Automatically generated nanopb constant definitions */ | ||||
| /* Generated by nanopb-0.4.5 */ | ||||
| 
 | ||||
| #include "application.pb.h" | ||||
| #if PB_PROTO_HEADER_VERSION != 40 | ||||
| #error Regenerate this file with the current version of nanopb generator. | ||||
| #endif | ||||
| 
 | ||||
| PB_BIND(PB_App_Start, PB_App_Start, AUTO) | ||||
| 
 | ||||
| 
 | ||||
| PB_BIND(PB_App_LockStatusRequest, PB_App_LockStatusRequest, AUTO) | ||||
| 
 | ||||
| 
 | ||||
| PB_BIND(PB_App_LockStatusResponse, PB_App_LockStatusResponse, AUTO) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										79
									
								
								assets/compiled/application.pb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								assets/compiled/application.pb.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| /* Automatically generated nanopb header */ | ||||
| /* Generated by nanopb-0.4.5 */ | ||||
| 
 | ||||
| #ifndef PB_PB_APP_APPLICATION_PB_H_INCLUDED | ||||
| #define PB_PB_APP_APPLICATION_PB_H_INCLUDED | ||||
| #include <pb.h> | ||||
| 
 | ||||
| #if PB_PROTO_HEADER_VERSION != 40 | ||||
| #error Regenerate this file with the current version of nanopb generator. | ||||
| #endif | ||||
| 
 | ||||
| /* Struct definitions */ | ||||
| typedef struct _PB_App_LockStatusRequest {  | ||||
|     char dummy_field; | ||||
| } PB_App_LockStatusRequest; | ||||
| 
 | ||||
| typedef struct _PB_App_Start {  | ||||
|     char *name;  | ||||
|     char *args;  | ||||
| } PB_App_Start; | ||||
| 
 | ||||
| typedef struct _PB_App_LockStatusResponse {  | ||||
|     bool locked;  | ||||
| } PB_App_LockStatusResponse; | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Initializer values for message structs */ | ||||
| #define PB_App_Start_init_default                {NULL, NULL} | ||||
| #define PB_App_LockStatusRequest_init_default    {0} | ||||
| #define PB_App_LockStatusResponse_init_default   {0} | ||||
| #define PB_App_Start_init_zero                   {NULL, NULL} | ||||
| #define PB_App_LockStatusRequest_init_zero       {0} | ||||
| #define PB_App_LockStatusResponse_init_zero      {0} | ||||
| 
 | ||||
| /* Field tags (for use in manual encoding/decoding) */ | ||||
| #define PB_App_Start_name_tag                    1 | ||||
| #define PB_App_Start_args_tag                    2 | ||||
| #define PB_App_LockStatusResponse_locked_tag     1 | ||||
| 
 | ||||
| /* Struct field encoding specification for nanopb */ | ||||
| #define PB_App_Start_FIELDLIST(X, a) \ | ||||
| X(a, POINTER,  SINGULAR, STRING,   name,              1) \ | ||||
| X(a, POINTER,  SINGULAR, STRING,   args,              2) | ||||
| #define PB_App_Start_CALLBACK NULL | ||||
| #define PB_App_Start_DEFAULT NULL | ||||
| 
 | ||||
| #define PB_App_LockStatusRequest_FIELDLIST(X, a) \ | ||||
| 
 | ||||
| #define PB_App_LockStatusRequest_CALLBACK NULL | ||||
| #define PB_App_LockStatusRequest_DEFAULT NULL | ||||
| 
 | ||||
| #define PB_App_LockStatusResponse_FIELDLIST(X, a) \ | ||||
| X(a, STATIC,   SINGULAR, BOOL,     locked,            1) | ||||
| #define PB_App_LockStatusResponse_CALLBACK NULL | ||||
| #define PB_App_LockStatusResponse_DEFAULT NULL | ||||
| 
 | ||||
| extern const pb_msgdesc_t PB_App_Start_msg; | ||||
| extern const pb_msgdesc_t PB_App_LockStatusRequest_msg; | ||||
| extern const pb_msgdesc_t PB_App_LockStatusResponse_msg; | ||||
| 
 | ||||
| /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ | ||||
| #define PB_App_Start_fields &PB_App_Start_msg | ||||
| #define PB_App_LockStatusRequest_fields &PB_App_LockStatusRequest_msg | ||||
| #define PB_App_LockStatusResponse_fields &PB_App_LockStatusResponse_msg | ||||
| 
 | ||||
| /* Maximum encoded size of messages (where known) */ | ||||
| /* PB_App_Start_size depends on runtime parameters */ | ||||
| #define PB_App_LockStatusRequest_size            0 | ||||
| #define PB_App_LockStatusResponse_size           2 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <pb.h> | ||||
| #include "storage.pb.h" | ||||
| #include "status.pb.h" | ||||
| #include "application.pb.h" | ||||
| 
 | ||||
| #if PB_PROTO_HEADER_VERSION != 40 | ||||
| #error Regenerate this file with the current version of nanopb generator. | ||||
| @ -28,7 +29,9 @@ typedef enum _PB_CommandStatus { | ||||
|     PB_CommandStatus_ERROR_STORAGE_INVALID_NAME = 10, /* *< Invalid name/path */ | ||||
|     PB_CommandStatus_ERROR_STORAGE_INTERNAL = 11, /* *< Internal error */ | ||||
|     PB_CommandStatus_ERROR_STORAGE_NOT_IMPLEMENTED = 12, /* *< Functon not implemented */ | ||||
|     PB_CommandStatus_ERROR_STORAGE_ALREADY_OPEN = 13 /* *< File/Dir already opened */ | ||||
|     PB_CommandStatus_ERROR_STORAGE_ALREADY_OPEN = 13, /* *< File/Dir already opened */ | ||||
|     PB_CommandStatus_ERROR_APP_CANT_START = 16, /* *< Can't start app - either wrong name, or internal error */ | ||||
|     PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED = 17 /* *<  Another app is running */ | ||||
| } PB_CommandStatus; | ||||
| 
 | ||||
| /* Struct definitions */ | ||||
| @ -58,14 +61,17 @@ typedef struct _PB_Main { | ||||
|         PB_Storage_MkdirRequest storage_mkdir_request; | ||||
|         PB_Storage_Md5sumRequest storage_md5sum_request; | ||||
|         PB_Storage_Md5sumResponse storage_md5sum_response; | ||||
|         PB_App_Start app_start; | ||||
|         PB_App_LockStatusRequest app_lock_status_request; | ||||
|         PB_App_LockStatusResponse app_lock_status_response; | ||||
|     } content;  | ||||
| } PB_Main; | ||||
| 
 | ||||
| 
 | ||||
| /* Helper constants for enums */ | ||||
| #define _PB_CommandStatus_MIN PB_CommandStatus_OK | ||||
| #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_INVALID_PARAMETERS | ||||
| #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_INVALID_PARAMETERS+1)) | ||||
| #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED | ||||
| #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED+1)) | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| @ -94,6 +100,9 @@ extern "C" { | ||||
| #define PB_Main_storage_mkdir_request_tag        13 | ||||
| #define PB_Main_storage_md5sum_request_tag       14 | ||||
| #define PB_Main_storage_md5sum_response_tag      15 | ||||
| #define PB_Main_app_start_tag                    16 | ||||
| #define PB_Main_app_lock_status_request_tag      17 | ||||
| #define PB_Main_app_lock_status_response_tag     18 | ||||
| 
 | ||||
| /* Struct field encoding specification for nanopb */ | ||||
| #define PB_Empty_FIELDLIST(X, a) \ | ||||
| @ -116,7 +125,10 @@ X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_write_request,content.storag | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_delete_request,content.storage_delete_request),  12) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_mkdir_request,content.storage_mkdir_request),  13) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_md5sum_request,content.storage_md5sum_request),  14) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_md5sum_response,content.storage_md5sum_response),  15) | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_md5sum_response,content.storage_md5sum_response),  15) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,app_start,content.app_start),  16) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,app_lock_status_request,content.app_lock_status_request),  17) \ | ||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,app_lock_status_response,content.app_lock_status_response),  18) | ||||
| #define PB_Main_CALLBACK NULL | ||||
| #define PB_Main_DEFAULT NULL | ||||
| #define PB_Main_content_empty_MSGTYPE PB_Empty | ||||
| @ -131,6 +143,9 @@ X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_md5sum_response,content.stor | ||||
| #define PB_Main_content_storage_mkdir_request_MSGTYPE PB_Storage_MkdirRequest | ||||
| #define PB_Main_content_storage_md5sum_request_MSGTYPE PB_Storage_Md5sumRequest | ||||
| #define PB_Main_content_storage_md5sum_response_MSGTYPE PB_Storage_Md5sumResponse | ||||
| #define PB_Main_content_app_start_MSGTYPE PB_App_Start | ||||
| #define PB_Main_content_app_lock_status_request_MSGTYPE PB_App_LockStatusRequest | ||||
| #define PB_Main_content_app_lock_status_response_MSGTYPE PB_App_LockStatusResponse | ||||
| 
 | ||||
| extern const pb_msgdesc_t PB_Empty_msg; | ||||
| extern const pb_msgdesc_t PB_Main_msg; | ||||
| @ -141,9 +156,9 @@ extern const pb_msgdesc_t PB_Main_msg; | ||||
| 
 | ||||
| /* Maximum encoded size of messages (where known) */ | ||||
| #define PB_Empty_size                            0 | ||||
| #if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) | ||||
| #if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_Start_size) | ||||
| #define PB_Main_size                             (10 + sizeof(union PB_Main_content_size_union)) | ||||
| union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f0[36];}; | ||||
| union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_Start_size)]; char f0[36];}; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 41599b8e6a6b33a229e8f5fa58de1a2cfcc8184a | ||||
| Subproject commit 8e6db414beed5aff0902f2cca2f4146a0dffb7a1 | ||||
| @ -56,7 +56,7 @@ void subghz_protocol_came_twee_free(SubGhzProtocolCameTwee* instance) { | ||||
| LevelDuration subghz_protocol_came_twee_add_duration_to_upload( | ||||
|     SubGhzProtocolCameTwee* instance, | ||||
|     ManchesterEncoderResult result) { | ||||
|     LevelDuration data; | ||||
|     LevelDuration data = {.duration = 0, .level = 0}; | ||||
|     switch(result) { | ||||
|     case ManchesterEncoderResultShortLow: | ||||
|         data.duration = instance->common.te_short; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov