diff --git a/ChangeLog.md b/ChangeLog.md index 206b2e259..8a8f39d25 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -19,7 +19,9 @@ - FBT: New `SKIP_EXTERNAL` toggle and `EXTRA_EXT_APPS` config option (by @Willy-JL) - Desktop: Added TV animation from OFW which was missing (internal on OFW) - UL: BadKB: Add Finnish keyboard layout (by @nicou) -- OFW: Furi: Event loop (by @skotopes) +- Furi: + - OFW: Event loop (by @skotopes) + - OFW: Thread signals, loader close, loader get app name (by @gsurkov) - OFW: RPC: Add TarExtract command, some small fixes (by @Willy-JL) - OFW: USB/CCID: Add initial ISO7816 support (by @kidbomb) - OFW: FBT/VsCode: Tweaks for cdb generation for clangd (by @hedger) @@ -63,8 +65,10 @@ - OFW: ReadMe: update outdated bits and pieces (by @skotopes) ### Removed: -- Furi: Temp disabled `FURI_TRACE` due to DFU size, some crashes will say "furi_check failed" instead of source path -- Furi: Reverted TLSF allocator due to diminishing results on RAM usage -- API: Removed `Rgb565Color` and `rgb565cmp()` since VGM colors use normal RGB colors now -- API: Removed unused `furi_hal_usb_get_config_context()` function +- Furi: + - Temp disabled `FURI_TRACE` due to DFU size, some crashes will say "furi_check failed" instead of source path + - Reverted TLSF allocator due to diminishing results on RAM usage +- API: + - Removed unused `Rgb565Color` and `rgb565cmp()` since VGM colors use normal RGB colors now + - Removed unused `furi_hal_usb_get_config_context()` function since BadKB doesn't use it anymore - OFW: CLI: Removed `ps` command, replaced by `top` diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index b7acfc667..0e8be86bd 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -84,11 +84,6 @@ void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { view_dispatcher); } -void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { - furi_check(view_dispatcher); - view_dispatcher->event_context = context; -} - void view_dispatcher_set_navigation_event_callback( ViewDispatcher* view_dispatcher, ViewDispatcherNavigationEventCallback callback) { @@ -112,6 +107,11 @@ void view_dispatcher_set_tick_event_callback( view_dispatcher->tick_period = tick_period; } +void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { + furi_check(view_dispatcher); + view_dispatcher->event_context = context; +} + FuriEventLoop* view_dispatcher_get_event_loop(ViewDispatcher* view_dispatcher) { furi_check(view_dispatcher); furi_check(view_dispatcher->event_loop); diff --git a/applications/services/gui/view_dispatcher.h b/applications/services/gui/view_dispatcher.h index 7627e5a0b..905c60975 100644 --- a/applications/services/gui/view_dispatcher.h +++ b/applications/services/gui/view_dispatcher.h @@ -107,7 +107,7 @@ void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, * in view_dispatcher_run. * * You can add your objects into event_loop instance, but don't run the loop on - * your side it will cause issues with input processing on dispatcher stop. + * your side as it will cause issues with input processing on dispatcher stop. * * @param view_dispatcher ViewDispatcher instance * diff --git a/applications/services/gui/view_dispatcher_i.h b/applications/services/gui/view_dispatcher_i.h index 5845f5a95..37571cf3c 100644 --- a/applications/services/gui/view_dispatcher_i.h +++ b/applications/services/gui/view_dispatcher_i.h @@ -11,7 +11,7 @@ #include "view_i.h" #include "gui_i.h" -DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) +DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) // NOLINT struct ViewDispatcher { FuriEventLoop* event_loop; diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 8118a6d60..6c871c5c1 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -273,6 +273,43 @@ MenuAppList_t* loader_get_menu_apps(Loader* loader) { return &loader->menu_apps; } +bool loader_signal(Loader* loader, uint32_t signal, void* arg) { + furi_check(loader); + + LoaderMessageBoolResult result; + + LoaderMessage message = { + .type = LoaderMessageTypeSignal, + .api_lock = api_lock_alloc_locked(), + .signal.signal = signal, + .signal.arg = arg, + .bool_value = &result, + }; + + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + + return result.value; +} + +bool loader_get_application_name(Loader* loader, FuriString* name) { + furi_check(loader); + + LoaderMessageBoolResult result; + + LoaderMessage message = { + .type = LoaderMessageTypeGetApplicationName, + .api_lock = api_lock_alloc_locked(), + .application_name = name, + .bool_value = &result, + }; + + furi_message_queue_put(loader->queue, &message, FuriWaitForever); + api_lock_wait_unlock_and_free(message.api_lock); + + return result.value; +} + // callbacks static void loader_menu_closed_callback(void* context) { @@ -858,6 +895,28 @@ static void loader_do_app_closed(Loader* loader) { furi_pubsub_publish(loader->pubsub, &event); } +static bool loader_is_application_running(Loader* loader) { + FuriThread* app_thread = loader->app.thread; + return app_thread && (app_thread != (FuriThread*)LOADER_MAGIC_THREAD_VALUE); +} + +static bool loader_do_signal(Loader* loader, uint32_t signal, void* arg) { + if(loader_is_application_running(loader)) { + return furi_thread_signal(loader->app.thread, signal, arg); + } + + return false; +} + +static bool loader_do_get_application_name(Loader* loader, FuriString* name) { + if(loader_is_application_running(loader)) { + furi_string_set(name, furi_thread_get_name(loader->app.thread)); + return true; + } + + return false; +} + // app int32_t loader_srv(void* p) { @@ -921,6 +980,16 @@ int32_t loader_srv(void* p) { case LoaderMessageTypeApplicationsClosed: loader_do_applications_closed(loader); break; + case LoaderMessageTypeSignal: + message.bool_value->value = + loader_do_signal(loader, message.signal.signal, message.signal.arg); + api_lock_unlock(message.api_lock); + break; + case LoaderMessageTypeGetApplicationName: + message.bool_value->value = + loader_do_get_application_name(loader, message.application_name); + api_lock_unlock(message.api_lock); + break; } } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 0223cfffd..83926a2f5 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -94,6 +94,26 @@ void loader_show_settings(Loader* instance); */ FuriPubSub* loader_get_pubsub(Loader* instance); +/** + * @brief Send a signal to the currently running application + * + * @param[in] instance pointer to the loader instance + * @param[in] signal signal value to be sent + * @param[in,out] arg optional argument (can be of any value, including NULL) + * + * @return true if the signal was handled by the application, false otherwise + */ +bool loader_signal(Loader* instance, uint32_t signal, void* arg); + +/** + * @brief Get the name of the currently running application + * + * @param[in] instance pointer to the loader instance + * @param[in,out] name pointer to the string to contain the name (must be allocated) + * @return true if it was possible to get an application name, false otherwise + */ +bool loader_get_application_name(Loader* instance, FuriString* name); + #ifdef __cplusplus } #endif diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c index a41e9ee99..ef530556d 100644 --- a/applications/services/loader/loader_cli.c +++ b/applications/services/loader/loader_cli.c @@ -1,9 +1,10 @@ +#include "loader.h" + #include #include #include #include #include -#include "loader.h" static void loader_cli_print_usage(void) { printf("Usage:\r\n"); @@ -12,6 +13,8 @@ static void loader_cli_print_usage(void) { printf("\tlist\t - List available applications\r\n"); printf("\topen \t - Open application by name\r\n"); printf("\tinfo\t - Show loader state\r\n"); + printf("\tclose\t - Close the current application\r\n"); + printf("\tsignal [arg:hex]\t - Send a signal with an optional argument\r\n"); } static void loader_cli_list(void) { @@ -29,12 +32,15 @@ static void loader_cli_list(void) { } static void loader_cli_info(Loader* loader) { - if(!loader_is_locked(loader)) { + FuriString* app_name = furi_string_alloc(); + + if(!loader_get_application_name(loader, app_name)) { printf("No application is running\r\n"); } else { - // TODO FL-3513: print application name ??? - printf("Application is running\r\n"); + printf("Application \"%s\" is running\r\n", furi_string_get_cstr(app_name)); } + + furi_string_free(app_name); } static void loader_cli_open(FuriString* args, Loader* loader) { @@ -58,9 +64,11 @@ static void loader_cli_open(FuriString* args, Loader* loader) { if(loader_start(loader, app_name_str, args_str, error_message) != LoaderStatusOk) { printf("%s\r\n", furi_string_get_cstr(error_message)); } else { - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - notification_message(notifications, &sequence_display_backlight_on); +#ifdef SRV_NOTIFICATION + NotificationApp* notification_srv = furi_record_open(RECORD_NOTIFICATION); + notification_message(notification_srv, &sequence_display_backlight_on); furi_record_close(RECORD_NOTIFICATION); +#endif } furi_string_free(error_message); } while(false); @@ -68,6 +76,38 @@ static void loader_cli_open(FuriString* args, Loader* loader) { furi_string_free(app_name); } +static void loader_cli_close(Loader* loader) { + FuriString* app_name = furi_string_alloc(); + + if(!loader_get_application_name(loader, app_name)) { + printf("No application is running\r\n"); + } else if(!loader_signal(loader, FuriSignalExit, NULL)) { + printf("Application \"%s\" has to be closed manually\r\n", furi_string_get_cstr(app_name)); + } else { + printf("Application \"%s\" was closed\r\n", furi_string_get_cstr(app_name)); + } + + furi_string_free(app_name); +} + +static void loader_cli_signal(FuriString* args, Loader* loader) { + uint32_t signal; + void* arg = NULL; + + if(!sscanf(furi_string_get_cstr(args), "%lu %p", &signal, &arg)) { + printf("Signal must be a decimal number\r\n"); + } else if(!loader_is_locked(loader)) { + printf("No application is running\r\n"); + } else { + const bool is_handled = loader_signal(loader, signal, arg); + printf( + "Signal %lu with argument 0x%p was %s\r\n", + signal, + arg, + is_handled ? "handled" : "ignored"); + } +} + static void loader_cli(Cli* cli, FuriString* args, void* context) { UNUSED(cli); UNUSED(context); @@ -76,29 +116,21 @@ static void loader_cli(Cli* cli, FuriString* args, void* context) { FuriString* cmd; cmd = furi_string_alloc(); - do { - if(!args_read_string_and_trim(args, cmd)) { - loader_cli_print_usage(); - break; - } - - if(furi_string_cmp_str(cmd, "list") == 0) { - loader_cli_list(); - break; - } - - if(furi_string_cmp_str(cmd, "open") == 0) { - loader_cli_open(args, loader); - break; - } - - if(furi_string_cmp_str(cmd, "info") == 0) { - loader_cli_info(loader); - break; - } - + if(!args_read_string_and_trim(args, cmd)) { loader_cli_print_usage(); - } while(false); + } else if(furi_string_equal(cmd, "list")) { + loader_cli_list(); + } else if(furi_string_equal(cmd, "open")) { + loader_cli_open(args, loader); + } else if(furi_string_equal(cmd, "info")) { + loader_cli_info(loader); + } else if(furi_string_equal(cmd, "close")) { + loader_cli_close(loader); + } else if(furi_string_equal(cmd, "signal")) { + loader_cli_signal(args, loader); + } else { + loader_cli_print_usage(); + } furi_string_free(cmd); furi_record_close(RECORD_LOADER); diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 7db3feed9..ac89ed7c4 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -34,6 +34,8 @@ typedef enum { LoaderMessageTypeUnlock, LoaderMessageTypeIsLocked, LoaderMessageTypeStartByNameDetachedWithGuiError, + LoaderMessageTypeSignal, + LoaderMessageTypeGetApplicationName, LoaderMessageTypeShowSettings, } LoaderMessageType; @@ -44,6 +46,11 @@ typedef struct { FuriString* error_message; } LoaderMessageStartByName; +typedef struct { + uint32_t signal; + void* arg; +} LoaderMessageSignal; + typedef enum { LoaderStatusErrorUnknown, LoaderStatusErrorInvalidFile, @@ -70,6 +77,8 @@ typedef struct { union { LoaderMessageStartByName start; + LoaderMessageSignal signal; + FuriString* application_name; }; union { diff --git a/furi/core/base.h b/furi/core/base.h index 92a52a797..e89065a7d 100644 --- a/furi/core/base.h +++ b/furi/core/base.h @@ -40,6 +40,12 @@ typedef enum { FuriStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. } FuriStatus; +typedef enum { + FuriSignalExit, /**< Request (graceful) exit. */ + // Other standard signals may be added in the future + FuriSignalCustom = 100, /**< Custom signal values start from here. */ +} FuriSignal; + #ifdef __cplusplus } #endif diff --git a/furi/core/event_loop.c b/furi/core/event_loop.c index b939695dd..f38a67657 100644 --- a/furi/core/event_loop.c +++ b/furi/core/event_loop.c @@ -149,6 +149,9 @@ void furi_event_loop_run(FuriEventLoop* instance) { furi_check(instance); furi_check(instance->thread_id == furi_thread_get_current_id()); + furi_thread_set_signal_callback( + instance->thread_id, furi_event_loop_signal_callback, instance); + uint32_t timeout = instance->tick_callback ? instance->tick_interval : FuriWaitForever; while(true) { @@ -194,11 +197,12 @@ void furi_event_loop_run(FuriEventLoop* instance) { } instance->state = FuriEventLoopStateIdle; } + + furi_thread_set_signal_callback(instance->thread_id, NULL, NULL); } void furi_event_loop_stop(FuriEventLoop* instance) { furi_check(instance); - furi_check(instance->thread_id == furi_thread_get_current_id()); xTaskNotifyIndexed( instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagStop, eSetBits); @@ -366,4 +370,19 @@ void furi_event_loop_link_notify(FuriEventLoopLink* instance, FuriEventLoopEvent } FURI_CRITICAL_EXIT(); -} \ No newline at end of file +} + +bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context) { + furi_assert(context); + FuriEventLoop* instance = context; + UNUSED(arg); + + switch(signal) { + case FuriSignalExit: + furi_event_loop_stop(instance); + return true; + // Room for possible other standard signal handlers + default: + return false; + } +} diff --git a/furi/core/event_loop_i.h b/furi/core/event_loop_i.h index 8ddd10966..5c0b144a1 100644 --- a/furi/core/event_loop_i.h +++ b/furi/core/event_loop_i.h @@ -28,6 +28,8 @@ typedef struct { const FuriEventLoopContractGetLevel get_level; } FuriEventLoopContract; +bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context); + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index a6b78f3f0..ab22fdf88 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -267,6 +267,29 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) { return thread->state; } +void furi_thread_set_signal_callback( + FuriThread* thread, + FuriThreadSignalCallback callback, + void* context) { + furi_check(thread); + furi_check(thread->state == FuriThreadStateStopped || thread == furi_thread_get_current()); + + thread->signal_callback = callback; + thread->signal_context = context; +} + +bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg) { + furi_check(thread); + + bool is_consumed = false; + + if(thread->signal_callback) { + is_consumed = thread->signal_callback(signal, arg, thread->signal_context); + } + + return is_consumed; +} + void furi_thread_start(FuriThread* thread) { furi_check(thread); furi_check(thread->callback); diff --git a/furi/core/thread.h b/furi/core/thread.h index 9c113bd49..be09e040e 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -86,6 +86,18 @@ typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); */ typedef void (*FuriThreadStateCallback)(FuriThreadState state, void* context); +/** + * @brief Signal handler callback function pointer type. + * + * The function to be used as a signal handler callback MUS follow this signature. + * + * @param[in] signal value of the signal to be handled by the recipient + * @param[in,out] arg optional argument (can be of any value, including NULL) + * @param[in,out] context pointer to a user-specified object + * @returns true if the signal was handled, false otherwise + */ +typedef bool (*FuriThreadSignalCallback)(uint32_t signal, void* arg, void* context); + /** * @brief Create a FuriThread instance. * @@ -255,6 +267,29 @@ void furi_thread_set_state_context(FuriThread* thread, void* context); */ FuriThreadState furi_thread_get_state(FuriThread* thread); +/** + * @brief Set a signal handler callback for a FuriThread instance. + * + * The thread MUST be stopped when calling this function. + * + * @param[in,out] thread pointer to the FuriThread instance to be modified + * @param[in] callback pointer to a user-specified callback function + * @param[in] context pointer to a user-specified object (will be passed to the callback, can be NULL) + */ +void furi_thread_set_signal_callback( + FuriThread* thread, + FuriThreadSignalCallback callback, + void* context); + +/** + * @brief Send a signal to a FuriThread instance. + * + * @param[in] thread pointer to the FuriThread instance to be signaled + * @param[in] signal signal value to be sent + * @param[in,out] arg optional argument (can be of any value, including NULL) + */ +bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg); + /** * @brief Start a FuriThread instance. * diff --git a/furi/core/thread_i.h b/furi/core/thread_i.h index 6299f3663..0a86a0678 100644 --- a/furi/core/thread_i.h +++ b/furi/core/thread_i.h @@ -24,6 +24,9 @@ struct FuriThread { FuriThreadStateCallback state_callback; void* state_context; + FuriThreadSignalCallback signal_callback; + void* signal_context; + char* name; char* appid; diff --git a/scripts/distfap.py b/scripts/distfap.py deleted file mode 100755 index b1c558790..000000000 --- a/scripts/distfap.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 - -import os -import posixpath - -from flipper.app import App -from flipper.storage import FlipperStorage, FlipperStorageOperations -from flipper.utils.cdc import resolve_port - - -class Main(App): - def init(self): - self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") - self.parser.add_argument( - "-n", - "--no-launch", - dest="launch_app", - action="store_false", - help="Don't launch app", - ) - - self.parser.add_argument("fap_src_path", help="App file to upload") - self.parser.add_argument( - "--fap_dst_dir", help="Upload path", default="/ext/apps", required=False - ) - self.parser.set_defaults(func=self.install) - - def install(self): - if not (port := resolve_port(self.logger, self.args.port)): - return 1 - - try: - with FlipperStorage(port) as storage: - storage_ops = FlipperStorageOperations(storage) - fap_local_path = self.args.fap_src_path - self.args.fap_dst_dir = self.args.fap_dst_dir.rstrip("/\\") - - if not os.path.isfile(fap_local_path): - self.logger.error( - f"Error: source .fap ({fap_local_path}) not found" - ) - return 2 - - fap_dst_path = posixpath.join( - self.args.fap_dst_dir, os.path.basename(fap_local_path) - ) - - self.logger.info(f'Installing "{fap_local_path}" to {fap_dst_path}') - - storage_ops.recursive_send(fap_dst_path, fap_local_path, False) - - if not self.args.launch_app: - return 0 - - storage.send_and_wait_eol(f"loader open {fap_dst_path}\r") - - if len(result := storage.read.until(storage.CLI_EOL)): - self.logger.error(f"Unexpected response: {result.decode('ascii')}") - return 3 - return 0 - - except Exception as e: - self.logger.error(f"Error: {e}") - # raise - return 4 - - -if __name__ == "__main__": - Main()() diff --git a/scripts/runfap.py b/scripts/runfap.py index 42141acff..b4b5989aa 100755 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -2,6 +2,7 @@ import operator from functools import reduce +import time from flipper.app import App from flipper.storage import FlipperStorage, FlipperStorageOperations @@ -9,6 +10,8 @@ from flipper.utils.cdc import resolve_port class Main(App): + APP_POST_CLOSE_DELAY_SEC = 0.2 + def init(self): self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument( @@ -67,6 +70,23 @@ class Main(App): if self.args.host_app: startup_command = self.args.host_app + self.logger.info("Closing current app, if any") + for _ in range(10): + storage.send_and_wait_eol("loader close\r") + result = storage.read.until(storage.CLI_EOL) + if b"was closed" in result: + self.logger.info("App closed") + storage.read.until(storage.CLI_EOL) + time.sleep(self.APP_POST_CLOSE_DELAY_SEC) + elif result.startswith(b"No application"): + storage.read.until(storage.CLI_EOL) + break + else: + self.logger.error( + f"Unexpected response: {result.decode('ascii')}" + ) + return 4 + self.logger.info(f"Launching app: {startup_command}") storage.send_and_wait_eol(f"loader open {startup_command}\r") diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 99c153c04..7150b68f4 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1627,10 +1627,12 @@ Function,+,furi_thread_set_context,void,"FuriThread*, void*" Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" +Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCallback, void*" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -1782,10 +1784,12 @@ Function,-,llrintl,long long int,long double Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double +Function,+,loader_get_application_name,_Bool,"Loader*, FuriString*" Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* Function,+,loader_show_menu,void,Loader* +Function,+,loader_signal,_Bool,"Loader*, uint32_t, void*" Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*" Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e60ee7514..c2c999f2e 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1934,10 +1934,12 @@ Function,+,furi_thread_set_context,void,"FuriThread*, void*" Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" +Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCallback, void*" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" @@ -2300,11 +2302,13 @@ Function,-,llrintl,long long int,long double Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double +Function,+,loader_get_application_name,_Bool,"Loader*, FuriString*" Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* Function,+,loader_show_menu,void,Loader* Function,+,loader_show_settings,void,Loader* +Function,+,loader_signal,_Bool,"Loader*, uint32_t, void*" Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*" Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*"